在对两个Integer类型的对象用==判断是否相等时发现了一点问题,代码如下:
Integer temp1 = 100;
Integer temp2 = 100;
Integer temp3 = 200;
Integer temp4 = 200;
System.out.println("temp1==temp2:");
System.out.println(temp1==temp2);
System.out.println("temp3==temp4:");
System.out.println(temp3==temp4);
运行结果如下:
一、问题产生原因
在两个值相等的Integer类型的对象使用==进行比较的时候,预期结果应该是返回为true,但一组返回了true,另一组返回了false。
二、理论分析
预期结果的依据是值相等,这其实是错误的。
如果是基本数据类型,可以通过==来进行值相等的判断。
不过本次使用的是包装类Integer来进行比较的,对比的不止值是否相等,还有这两个对象的地址是否相等。
这也就是为什么第二组数据输出的结果为false。
这也就引出了一个新的问题,同样是Integer包装类型的第一组数据为什么会返回true?这里就需要从源码的角度来解析一下了。
三、源码分析
1.自动拆箱
在分析源码之前要知道我们要找的源码来源于哪,为什么要找这块的代码。
这次的问题是要从初始化的时候开始分析的。
在上面的示例中我们用Integer定义的数其实是简写形式,正确的写法:(也就是自动装箱,这里不多进行阐述)
Integer temp1 = Integer.valueOf(100);
其他的几个数据也是一样的。这样我们就会发现,我们在最开始初始化的时候就调用了一个Integer包装类中的valueOf(int a)方法。这样我们就找到了需要去分析的部分,然后按住Ctrl用鼠标左键点击该方法就可以跳转到源码。
2.分析源码
下面就是valueOf()方法的源码,从源码中我们可以发现,这个方法对初始化时传入的int类型参数进行了一次判断,里面出现了一个 IntegerCache 类,并访问了它的三个常量。那我们的下一个目标就是先去这个类中分析一下具体有什么东西。
下面的是 IntegerCache 类的源码,里面的东西很多,但我们需要的其实只有其中的常量 low , high 和 cache[ ]。 low 的值直接给出为 -128,high 的值经过 static 中代码的执行后赋值,得到 high 的值为 127。cache[ ] 最后的取值为 -128 ~ 127。
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
这时我们再返回第一部分的源码分析,就会发现其判断区间为 -128 ~ 127。如果我们初始化时参数的值在这个区间,那么就会直接返回常量 cache 中的值等于该值的那个 Integer 类型的对象。这也就是为什么第一组数据返回的结果为true,因为这两个对象指向的其实都是 cache 中的同一个地址。而这个区间外的值则会开辟一个新的地址空间去存储,因此第二组的两个对象指向的地址一定是不同的,结果为false。
总结
这是我第一次尝试通过源码的方式来解决问题,过程可能会有很多不足,但也打开了一个新的方向,希望对大家有所帮助。