软件构造tips——int自动装箱的等价性
在复习软件构造的时候遇到了问题:int封装成Integer后的等价性。这个问题比较有趣,通过查看Integer源码,找到了其中的规律。
问题:
public static void main(String[] args){
Integer p1=new Integer(2);
Integer p2=new Integer(2);
System.out.println (p1==p2);
System.out.println (p1.equals(p2));
Integer p3=2;
Integer p4=2;
System.out.println (p3==p4);
System.out.println (p3.equals(p4));
Integer p5=200;
Integer p6=200;
System.out.println (p5==p6);
System.out.println (p5.equals(p6));
}
如图,代码分为三部分。第一部分是使用了new Integer直接构造新的Integer对象。第二部分是直接赋值一个小的整数。第三部分则是赋值一个大整数。那么这三种情况下代码的运行情况如何呢?他们的结果分别是:
false
true
true
true
false
true
为什么会有这样的结果呢?2和200得到的结果为什么是相反的呢?
解释
可以看到三种情况下equals方法得到的结果都是true,这是理所当然的,因为equals方法已经被重写。它只关心对象中储存的值是否相等。
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
但是对于==来说,结果分别是false ,true ,false。首先我们来分析第一种情况:
情况1
Integer p1=new Integer(2);
Integer p2=new Integer(2);
这种情况非常简单,因为p1,p2都是新建的Integer对象,他们的地址显然不同,那么==必然得到false。
情况2
Integer p3=2;
Integer p4=2;
我们必须先了解直接赋值法是如何创建与一个Integer对象的。查阅资料后,得知在该过程中调用了一个名为valueOf的方法:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这里有一个判断,如果传入的参数 i在[low ,high]范围内,此方法返回数组IntegerCache.cache中的一个对象,否则创建一个新对象。查看IntegerCache的源码后,我们得知IntegerCache的low定义为-128,high默认定义为127。也就是说如果参数i在这个范围内,该方法将直接拿到cache数组中现存的Integer而无需新建。如果在此范围之外,那么不好意思,你必须花费内存来储存你想要的i了。
那么对于本问题而言,因为我们给出的i是2,那么它将直接获得缓存数组的对象。因此p3与p4都将指向同一个地址,==的结果自然为true。
情况3
分析完情况2后这个也就一目了然了。因为我们给出的值是200。200已经超出了缓存数组的范围,必须新建两个对象,因此==的结果为false。
总结
在对老师ppt上提出的等价性问题进行挖掘后发现了生成Integer的有趣机制。这种缓存机制有利于在生成大量Integer对象时减少内存的消耗。比如淘宝网一天生成无数个-128——127之间的小整数,只需要一个地址就足够了。
遇到问题多看java源码,会有很多收获。