分析过程:
Integer i1 = 100;
先看看常量池里面有没有100,如果没有100,新建一个,如果有,直接引用。
Integer I2 = new Integer(100);
直接在堆内存申请一个新的内存空间,值为100,这时候,i1 和 i2 的内存地址就不一样了
int i3 = 100;
发现常量池已经出现过100了,直接拿来引用,所以 i1 == i3 结果为true,引用的地址是一样的。
Integer i4 = Integer.valueOf(100);
把int类型的100封装在Integer类里边,然而,这个100还是在常量池有的,仍然直接引用,所以i1 == i4 结果为true,引用地址是一样的。
Number i5 = 100;
Number是Integer的父类,而且是抽象类,有很多子类,例如Long、Short、Float等等的子类。
而这个100直接赋值给变量i5,编译器无法识别i5变量的子类是谁,只能识别父类,例如i5.equals() ,用ctrl点这个equals方法,你会发现跳转到Object类里面去了,如果用i5.getClass()就会发现,i5变量调用的其实是Integer类的equals方法。
所以,一个教训就是,不要随便使用ctrl点进去,随意相信编译器
Number i6 = new AtomicInteger(100);
这时候,i6.getClass()就是AtomicInteger类了,i6调用的是AtomicInteger类,AtomicInteger类没有重写equals方法,默认调用Object类的equals方法,i6.equals(i2)比较的就是指针,结果为false
Integer i1 = 100;
Integer i2 = new Integer(100);
int i3 = 100;
Integer i4 = Integer.valueOf(100);
Number i5 = 100;
Number i6 = new AtomicInteger(100);
System.out.print("(6)");System.out.println(i1 == i2); //false
System.out.print("(7)");System.out.println(i1 == i3); //true
System.out.print("(8)");System.out.println(i1 == i4); //true
System.out.print("(9)");System.out.println(i3 == i4); //true
System.out.print("(10)");System.out.println(i1 == i5); //true
System.out.println("(11)"+i2.equals(i5)); //true
/*i5 并没有重写equals方法,ctrl点进去发现是Object的equals,那么equals方法比较的就是指针,i5和i2的指针不同,这里打印为true
其实,是IDE无法知道Number的具体子类是哪一个,通过i5.getClass()以后,发现是Integer类,Integer类是重写了equals方法的
, 比较的是值,所以还是打印true
Number i5 = 100;还是要看具体赋值的是哪个子类,如果Number i5 = new AtomicInteger(100);那么其子类就是AtomicInteger,
然而AtomicInteger并没有重写equals方法,所以比较的还是指针,i6.equals(i2)结果为false
*/
System.out.println("(12)"+i5.equals(i2)); //true
System.out.println(i5.getClass());
System.out.print("(13)");System.out.println(i5 == i2); //false
System.out.print("(14)");System.out.println(i6.equals(i2)); //false
但是要注意的是,看看Integer的源码
当定义Integer i7 = 200; Integer i8 = 200;的时候,这时候System.out.println(i7 == i8); 就是false了。
定义Double d1 = 100.0; Double d2 = 100.0; 这时候 System.out.println(d1 == d2); 这时候还是false。是因为Double的源码告诉我们Double是直接new 一个对象的,新分配一个内存空间,不会在运行时常量池引用