之前在看一些java基础的面试题中,出现了一个Integer 自动封装及解封的相关问题。写如下代码:
public class MainClass {
public static void main(String[] args)
{
Integer int1 = Integer.valueOf(128);
Integer int2 = Integer.valueOf(128);
Integer int3 = Integer.valueOf(23);
Integer int4 = Integer.valueOf(23);
Integer int5 = int1;
System.out.println(int1 == int2);
System.out.println(int1 == 128);
System.out.println(int3 == int4);
System.out.println(int3 == 23);
}
}
得出结果:
false
true
true
true
在没看过源码的情况下会觉得比较奇怪。翻阅Integer源码会发现,Integer有一个IntegerCache内部类,默认会对 -128 到 127 之间的数进行缓存。另外我们还可以在JVM参数中设置 -XX:AutoBoxCacheMax=<size> 来设置缓存的范围,size的范围需要在128至 Integer.MAX_VALUE - (-low) -1。这样缓存的数是-128至size和(Integer.MAX_VALUE - (-low) -1)中较小的一个。
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() {}
}
Integer.valueOf(int i),方法实现如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们在通过 Integer.valueOf() 方法来获取一个Integer时,如果在我们的缓存区域内,就会直接从缓存中的对象获取。于是有System.out.println(int3 == int4) 输出为true,而System.out.println(int1 == int2)为false。
对开篇是代码进行调试,在进程结束前打上断点:
我们可以看到,int1和int2 值相同,但对应的并不是同一个地址@502及@503,因为Integer是对象类型,而不是基本类型,对其进行的 == 操作是判断这两个对象是不是指向同一个对象,因此返回为false。而int3和int4则是指向了同一个对象@504,对他们进行
== 操作返回为true。
至于自动解封的情况,应该是确切的需要接受基本类型的时候才会出现,我们的int5=int1操作中,我们的左值是一个Integer对象类型,而不是一个基础类型,所以直接将int5指向了int1,为同一个对象。