128 陷阱
128陷阱,简单来说就是对大于等于128和小于等于-129的数字,使用 Integer
类型存储(自动装箱)时候
使用 ==
进行比较地址,会返回 false
表现
public class Test {
public static void main(String[] args) {
Integer num1 = 127;
Integer num2 = 127;
System.out.println(num1 == num2);
Integer num3 = 128;
Integer num4 = 128;
System.out.println(num3 == num4);
Integer num5 = -128;
Integer num6 = -128;
System.out.println(num5 == num6);
Integer num7 = -129;
Integer num8 = -129;
System.out.println(num7 == num8);
}
}
输出结果为:
true
false
true
false
原因
产生128陷阱的原因,在于自动装箱的过程中,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);
}
其中 low
在源码中为:
static final int low = -128;
high
在源码中为:
static final int high;
虽然这样看 high
的初始值为 0
但在静态构造块中:
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;
}
为 high
赋值了 127
由此也得出了不会产生128陷阱情况的范围 [-128, 127]
现在再回到最初的 valueOf()
方法,可以看出,当结果在 [-128, 127]
之间的时候,会直接 return IntegerCache.cache[i + (-IntegerCache.low)];
而超出此范围的值,会 return new Integer(i)
会在内存中开辟一份新的空间,此时返回的值的内存地址就不会是一开始的内存地址了
现在我们再来看 IntegerCache.cache
static final Integer cache[];
而在静态构造快中又存在这样一部分:
cache = new Integer[(high - low) + 1]; // new Integer[127 + 128 + 1] -> new Integer[256]
int j = low; // j = -128
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
在源码的静态构造块中,创建了一个缓存数组,来存放 [-128, 127]
范围的数字
再次回到 valueOf()
源码查看,得出,当结果在 [-128, 127]
范围内是,直接返回的是一个数值,并非新创建了一个 Integer
实例,即 return 127;
返回这样的值。
故而得出了产生128陷阱的原因,归根结底就是源码中的缓存数组,如果这个数组变大了,那么就不会是128陷阱了,就变成更大的129陷阱,130陷阱等等了。