前置知识:两个对象==比较的是栈的值,"==" 在java中比较对象时永远是比较对象的地址,这一点绝不会错。众所周之,java是保留了int,char等基本数据类型的,也就是说int类型的并不是对象,然而有些方法却需要object 类型的变量,所以java使用了装箱机制,我们可以自豪的这样声明一个整型变量:Integer a = new Integer(10); 那么整型的a也就是对象了,那这句是什么意思呢:Integer a= 10; java中可以这样声明一个对象吗?当然不是,从jdk1.5后,java实现了自动装箱,也就是自动将Integer a =10 中的int类型的10转化为了 Integer类型。
好,有了前面的只是我们且先看一个题目:
Integer a = 127;Integer b = 127;Integer c = 128;Integer d = 128;System.out.println(a==b);System.out.println(c==d);答案是什么呢? 如果您回答true,false,那么很遗憾的告诉你,你答对了!!!
分析一下,Integer a =127,Integer a=128。127,128应该不会造成什么差异吧,难道是自动装箱的过程有猫腻?找下源码看看:
private static class IntegerCache { private IntegerCache(){ } static final Integer cache[] = new Integer[-(-128) + 127 + 1];static {
for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); } } public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); } }源码解释:当我们装箱时,jvm实际上是自动调用的valueOf()这个方法,也就是Integer a= 10相当于Integer.valueOf(10)。好,我们看下Integer a = 127 的执行过程,首先调用Integer.valueOf(127) ,由于127在-128到127之间(看上面的源码),所以返回一个缓存值 return IntegerCache.cache[127+128];也就是数组中下标是255的值,那这个到底是什么值呢? 我们继续看:
static { for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); }
这是用一个for循环对数组cache赋值,cache[255] = new Integer(255-128),也就是new一个Integer(127) ,并把引用赋值给cache[255],好了,然后是Integer b= 127,流程基本一样,最后又到了cache[255] = new Integer(255-128),这一句,有点迷糊了,这不是又new了一个对象127吗,然后把引用赋值给cache[255],我们比较这两个引用(前面声明a的时候也有一个),由于是不同的地址,所以肯定不会相等,应该返回false啊!这么想你就错了,请注意看for语句给cache[i]初始化的时候外面有一个{},{}前面一个大大的static关键字大咧咧的杵在哪呢,对静态的,那么我们就可以回想下static有什么特性:
只能初始化一次,在对象间共享,也就是不同的对象共享同一个static数据,那么当我们Integer b = 127的时候,并没有new出一个新对象来,而是共享了a这个对象的引用,记住,他们共享了同一个引用!!!,那么我们进行比较a==b时,由于是同一个对象的引用(它们在堆中的地址相同),那当然返回 true了!!!然后我们在看Integer c = 128;Integer d = 128;,当数据不再-128到127之间时,是不执行return IntegerCache.cache[i + offset];这句的,也就是不会返回一个static的引用,而是执行了return new Integer(i); 于是当 Integer d = 128 时,又会重新返回一个引用,两个不同的引用
在做c==d 的比较时当然返回false了!!/*===========================================================*/
public static void main(String[] args) {
Integer a = new Integer(1); Integer b = new Integer(1); int c=1; Integer e = 1; System.out.println("a==b:"+(a==b)); System.out.println("a==c:"+(a==c)); System.out.println("a==e:"+(a==e)); System.out.println("c==e:"+(c==e));}结果:a==b:falsea==c:truea==e:falsec==e:trueInteger是int的封装对象,两个对象==比较的是栈的值。Integer a = new Integer(1);Integer b = new Integer(1);a与b在栈中,存的是Integer对象在堆中的地址,而不是值。a、b指向堆中的地址显然不同所以 a==b 为false.int c = 1; int为值类型,引用类型Integer与值类型int比较显然比较的是值。因为int在堆中是不开辟内存的,他在栈中的值则为他本身的值所以a==c比较的是他们各自的value, a==c为trueInteger e=1; 这个比较特殊,直接赋值,它有独立的内存,每次赋值时将检查内存中是否有值跟他匹配的,若有则把此内存地址付给e,若没有,开辟新的内存。你可以尝试下面的例子:Integer t1 = 1;Integer t2 = 1;t1==t2 为true,如上所说,此时t1与t2指向的是同一块内存。new 一定是开辟新的内存,直接赋值则不一定开辟新的内存。因为a的引用指向堆,而e指向专门存放他的内存,所以他们的内存地址不一样。所以a==e为false.c==e等同于 a==c,一个引用类型一个值类型integer与integer比较的是引用的地址,integer与int,integer先拆箱,比较的是值。/*==========================================================*/
Integer 在自动装箱时调用了valueOf() 方法,其中IntegerCache 用来缓存Integer值的。默认缓存的Integer 值范围是 -128 ~ 127 。 我们来分析一下valueOf(int i)的执行过程: 如果 i 大于缓存中的 最小值(-127) 并且 小于 缓存中的最大值(127),直接返回IntegerCache 中缓存的Integer对象。否则就新建一个Integer对象并返回。
在-128~127之间时,装箱操作后,a 和 b 都是指向缓存中的同一个对象,结果返回true。其他情况下就不一样了,装箱操作时都是返回新的Integer对象,== 操作时地址必然不相等,所以返回false。 以后遇到数字比较时,要么先将值赋给对应的基本类型在比较,要么比较包装类型中的包装值(例如 a.intValue() == b.intValue()),要么直接调用equals方法。