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陷阱等等了。
本文详细解释了Java中的128陷阱现象,即在使用Integer类型进行值比较时,大于等于128和小于等于-129的数值通过`==`操作返回false。原因是Integer类的valueOf()方法会缓存-128到127之间的数值,超出此范围则会创建新的对象,导致内存地址不同。通过对Integer源码的分析,揭示了这一现象的根本原因在于IntegerCache缓存机制。
574

被折叠的 条评论
为什么被折叠?



