目录
基本数据类型和其对应的对象类比较
Float和Double之间微妙的关系
i++和++i
final
continue lable和break lable考察
构造方法,构造块,静态块,静态属性的输出顺序
方法栈,栈,堆的考察
try - finally的返回值
Integer a = 25;
Integer b = 25;
System.out.println(a == b); answer:true
System.out.println(a.equals(b)); answer:true
System.out.println(a.equals("25")); answer:false
System.out.println(a.equals(25)); answer:true
Integer a = 135;
Integer b = 135;
System.out.println(a == b); answer:false
System.out.println(a.equals(b)); answer:true
System.out.println(a.equals("135")); answer:false
System.out.println(a.equals(135)); answer:true
Integer a = new Integer(25);
Integer b = new Integer(25);
Long c = new Long(25);
System.out.println(a == b); answer:false
System.out.println(a == 25); answer:true //此时Integer会自动拆箱,转换成int,比
较的就只是数值了
System.out.println(c == 25); answer:true //Long自动拆箱,int会向上转型成long然
后进行比较
System.out.println(a.equals(b)); answer:true
System.out.println(a.equals("25")); answer:false
System.out.println(a.equals(25)); answer:true
Short a = 25;
Short b = 25;
System.out.println(a == b); answer:true
System.out.println(a.equals(b)); answer:true
System.out.println(a.equals("25")); answer:false
System.out.println(a.equals(25)); answer:false
P.S
以下是Integer类equals源码以及Integer自动装箱调用的ValueOf方法:另外Short的equals方法也列举了下来。
//Integer equal方法
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
//自動裝箱的方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) //IntegerCache.low = -128
return IntegerCache.cache[i + (-IntegerCache.low)];//IntegerCache.high = 127
return new Integer(i);
}
//Short equals方法
public boolean equals(Object obj) {
if (obj instanceof Short) {
return value == ((Short)obj).shortValue();
}
return false;
}
(1)Integer类equals源码:如果不是Obj是String类型的话,直接会返回false,Short同理。
(2)JVM会自动维护八种基本类型的常量池,int常量池中初始化-128~127的范围,所以当为Integer i=127时,在自动装箱过程中是取自常量池中的数值,而当Integer i=128时,128不在常量池范围内,所以在自动装箱过程中需new 128,所以地址不一样。
float i = 25; //编译通过
Float i = 25; //编译失败
Float i = 25f;//编译通过
float i = 25.5;//编译失败
float i = 25.5f;//编译通过
float i = 42E3;//编译失败
double i = 42E3;//编译通过
float i = 25.5D//编译失败
double i = 25.5D//编译通过
double i = 25.5//编译通过
----------------------------------------------------------------------
float i = 25;
System.out.print(i == 25);//true
public class Test{
public static void main(String [] args){
int i = 1;
int s = ++i;
int x= i++;
System.out.printLn(i);//3
System.out.printLn(s);//2
System.out.printLn(x);//2
}
}
PS:++i改变i也改变赋值变量,i++只改边i,不改变赋值变量。
class finalTest{
final int i;
public void doSomeThing(){
System.out.println("i="+i);
}
}
P.S:此段程序会报错,final修饰的成员变量必须手动赋值。如果把成员变量的final去掉,则不会报错,程序会给i设置默认值0;final修饰基本数据类型是不可以改变的,final修饰对象,对象引用不能改变,但是对象的内容可以改变。
label1: //位置1
while (true) {
// 位置二
for (int i = 0; i <= 8; i++) {
System.out.println("i=" + i);
if (i == 5) {
break label1;
}
}
System.out.println("WAIT UP");
}
PS:break label 则是可以跳出通过label的标签定义的代码块
lable1放在位置1,输出0,1,2,3,4
lable1放在位置2,输出0,1,2,3,4 WAIT UP ...循环
2.continue -- label
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
label1: for (int x = 0; x < 10; x++) {
System.out.println("x = " + x);
continue label1;
}
}
等于:
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
for (int x = 0; x < 10; x++) {
System.out.println("x = " + x);
}
}
---------------------------------------------------------------------------------------
label1: for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
for (int x = 0; x < 10; x++) {
System.out.println("x = " + x);
continue label1;
}
}
跳出循环,进入lable1标签循环,值:0,0,1,0,2,0...按照这个规则输出的
注意:label1:
for (int i = 1; i < 10; i++) {
lable2:
System.out.println("i="+i);
for (int j = 0; j < 10; j++) {
if(j == 9) continue label1;
}
}
continue后接的标签名,必须紧跟循环,如果将continue后的label1换成lable2则程序编译报错
public class App extends HelloA{
public App(){
System.out.println(9);
}
{
System.out.println(6);
}
static {
System.out.println(4);
}
private static int b = getStaticB();
public static int getStaticB(){
b = 10;
System.out.println(b);
return b;
}
public static void main(String[] args) {
System.out.println(1); //3,4,1,2,8,6,9,2,8,9,6,5
new App();
new App();
System.out.println("5");
}
}
class HelloA{
{
System.out.println(2);
}
public HelloA(){
System.out.println(8);
}
static {
System.out.println(3);
}
private static int a = getStaticA();
public static int getStaticA(){
a = 11;
System.out.println(a);
return a;
}
}
输出:3 11 4 10 1 2 8 6 9 2 8 6 9 5
结论:1.实例化子类的时候,若此类未被加载过,首先加载是父类的类对象,然后加载子类的类对象,接着实例化父类,最后实例化子类,若此类被加载过,不再加载父类和子类的类对象。2.当加载类对象时,首先执行静态块,然后初始化静态属性;当实例化对象时,首先执行构造块,然后执行构造方法。(构造块一定会在构造方法前执行)。
public class Example{
String str=new String("good");
char[]ch={'a','b','c'};
public static void main(String args[]){
Example ex=new Example();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+" and ");
Sytem.out.print(ex.ch);
}
public void change(String x,char y[]){
x="test ok";
y[0]='g';
}
}
答案是good and gbc
考察的其实是方法栈随着方法的消失,方法栈的变量也会消失;
public static void main(String[] args) {
int i = tryFinallyReturn();
System.out.println(i);
}
public static int tryFinallyReturn(){
int i = 0;
try{
return ++i;//位置1
}
finally {
i++;//位置2
}
}
//输出为1,如果位置1改成i++则输出为0
P.S:finally总会执行,这行顺序是位置1(这里会缓存一个临时变量),然后位置2,此时i的值为2,在重新执行到位置1,此时返回的是临时变量。所以位置2,无论做什么操作,其实对返回值都没有影响。
public static void main(String[] args) {
int i = tryFinallyReturn();
System.out.println(i);
}
public static int tryFinallyReturn(){
int i = 0;
try{
return ++i;//位置1
}
finally {
return ++i;//位置2
}
}
//此时返回的是2
P.S此时的执行顺序是,执行位置1,此时i会加1,执行到位置2时,程序就直接return了;