Java中的 “128陷阱“
目录
一、先明确:基本类型与包装类的区别
二、“128 陷阱” 的根源:Integer 缓存机制
三、代码示例:直观感受 “陷阱”
四、为什么会有这个缓存?
五、类似 “陷阱” 的其他包装类
六、如何避免 “陷阱”?
总结
当我们使用Integer类型比较两个值时,若两个相同的数字(假设都为66)都在-128-127范围内,使用“==”进行比较时,结果为true;但是两个数字一旦数字大于等于128,那么再次进行比较时,结果为false。
Java 的 “128 陷阱” 本质是 Integer 包装类的缓存机制导致的数值比较异常,核心与 Integer
类的 valueOf
方法缓存策略相关,以下是具体拆解:
一、先明确:基本类型与包装类的区别
int
:基本类型,存储具体数值,比较时用==
直接对比值。Integer
:int
的包装类,是对象类型,用==
对比的是对象的内存地址(而非值),值对比需用equals()
方法。
但实际开发中,用 Integer a = 123
这种 “自动装箱” 语法时,Java 会隐式调用 Integer.valueOf(123)
创建对象 —— 而 “128 陷阱” 就藏在这个方法里。
二、“128 陷阱” 的根源:Integer 缓存机制
为了优化性能,Java 在 Integer
类中预设了一个缓存池,缓存了 -128 ~ 127
范围内的 Integer 对象。
当调用 Integer.valueOf(n)
时:
- 若
n
在-128 ~ 127
之间:直接返回缓存池中的已有对象(Integer对象,且不会新建); - 若
n
超出这个范围:新建一个Integer
对象返回。
三、代码示例:直观感受 “陷阱”
public class Integer128Demo {public static void main(String[] args) {// 1. 数值在 -128~127 范围内:缓存生效,返回同一对象Integer a = 127; // 等价于 Integer.valueOf(127)Integer b = 127;System.out.println(a == b); // true(地址相同,缓存复用)System.out.println(a.equals(b)); // true(值相同)// 2. 数值超出范围(如 128):缓存不生效,新建对象Integer c = 128; // 等价于 Integer.valueOf(128)Integer d = 128;System.out.println(c == d); // false(地址不同,两个新对象)System.out.println(c.equals(d)); // true(值相同)// 3. 手动 new 对象:无论数值是否在范围内,都新建对象(不走缓存)Integer e = new Integer(127);Integer f = new Integer(127);System.out.println(e == f); // false(两个不同对象)}
}
四、为什么会有这个缓存?
- 性能优化:
-128 ~ 127
是日常开发中最常用的整数范围(如年龄、分数、索引等),缓存这些对象可以避免频繁创建 / 销毁小整数对象,减少内存开销,提升效率。 - 设计依据:这个范围是 Java 官方根据 “常用数值分布” 确定的,且
-128
是固定下限,上限 127 可以通过 JVM 参数-XX:AutoBoxCacheMax=<n>
自定义(如-XX:AutoBoxCacheMax=256
可将缓存上限扩展到 256)。
五、类似 “陷阱” 的其他包装类
除了 Integer
,Java 中还有其他包装类也有类似缓存机制(范围不同):
Byte
:缓存-128 ~ 127
(全部可能值,因为byte
范围就是这么大);Short
:缓存-128 ~ 127
;Long
:缓存-128 ~ 127
;Character
:缓存0 ~ 127
(ASCII 码范围内的字符);
Float
、Double
没有缓存(因为浮点数在任意范围内都有无限多个,缓存无意义)。
六、如何避免 “陷阱”?
核心原则:包装类对比值时,永远用 equals()
方法,而非 ==
。
即使数值在缓存范围内,也不要依赖 ==
对比 —— 避免因范围变化(如自定义缓存上限)或代码修改(如从 127
改成 128
)导致隐藏 bug。
// 正确写法:用 equals() 对比包装类的值
Integer x = 128;
Integer y = 128;
if (x.equals(y)) { // true,正确对比值System.out.println("值相同");
}// 注意:若可能为 null,需先判空(避免 NullPointerException)
Integer z = null;
if (z != null && z.equals(x)) { // 业务逻辑
}
总结
- “128 陷阱” 不是 bug,而是 Java 为优化性能设计的缓存机制导致的 “直觉不符” 现象;
- 本质是:
-128~127
的Integer
复用缓存对象,超出范围则新建对象,用==
对比地址会出现异常结果; - 解决方案:包装类对比值用
equals()
,基本类型对比用==
。