一、从概念了解128陷阱
在 Java 中,整型包装类 java.lang.Integer 存在一个 “128 陷阱”,具体指的是在范围为 -128 到 127 之间的整数值(包括 -128 和 127),在自动装箱(Autoboxing)时会被缓存,而超出这个范围的整数值则不会被缓存。这是由于 Integer 类在内部使用了一个缓存池(Cache),目的是为了提高性能和节省内存。( Java拆箱装箱)
当使用自动装箱或 Integer.valueOf() 方法将一个整数赋值给 Integer 类型的变量时,如果这个整数值在 -128 到 127 之间,将直接从缓存池中获取 Integer 对象,而不会创建新的对象。这样做的好处是可以重用已有的对象,减少了对象的创建和销毁开销。然而这种缓存机制可能导致128陷阱。
由于-128到127的整数数值是被缓存的,当你比较两个处于这个范围内的‘ Integer ’对象时,使用‘==’运算符时会返回true,因为他们引用的同一个缓存对象
代码示例:
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // 输出 true
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // 输出 false
返回结果:
二、从源码角度解析128陷阱
深入了解 java.lang.Integer 类中的实现细节。在 Java 中,整型包装类 Integer 是一个 final 类,它表示一个 32 位带符号的二进制补码整数。
Integer 类在内部使用了一个静态数组 IntegerCache,用于缓存范围在 -128 到 127 之间的 Integer 对象。这个缓存池的初始化默认大小是 -128 到 127,可以通过 JVM 参数java.lang.Integer
.IntegerCache.high 来调整上限。
打开Integer类可以看到相关代码:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// 调用 Integer.getInteger("java.lang.Integer.IntegerCache.high") 方法获取上限值
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);
// 使用 JVM 参数中的值来设置缓存上限
h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
} catch( NumberFormatException nfe) {
// 如果解析 JVM 参数失败,则使用默认的 127
// 同时也说明了 IntegerCache.high 参数是非公开的,不能直接通过代码设置
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 缓存数组被创建并初始化了 -128 到 127 范围内的 Integer 对象
// 超过此范围的整数值不会被缓存
}
private IntegerCache() {}
}
根据源码可以看到,如果使用自动装箱或者‘Integer.valueOf()’方法将一个整数类赋值给‘Integer’类型的变量时,如果整数值在-128-127之间,将直接从缓存池中获取对应的’Integer’对象里,如果超过了这个范围,将会重新创建一个新的’Integer’对象,而不是从缓存池中获取。
总结
“128 陷阱” 的原因:当整数值超过了 -128 到 127 范围时,两个不同的整数值被装箱后得到的 Integer 对象不再是同一个缓存对象,因此在使用 == 运算符比较时,会返回 false。而在范围内的整数值会从缓存池中获取,因此它们引用的是同一个缓存对象,使用 == 运算符比较时会返回 true。
如果想比较’Integer’对象,怎么做
使用equals()方法来比较Integer对象的值。具体参考友情链接,==与equals的区别
友情链接
【Java】==和 equals() 的区别:http://t.csdn.cn/Vtf42
【Java】拆箱和装箱(附示例代码讲解):http://t.csdn.cn/cS4bD