2019独角兽企业重金招聘Python工程师标准>>>
前置知识:两个对象==比较的是栈的值,"==" 在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:false
a==c:true
a==e:false
c==e:true
Integer是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为true
Integer 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方法。