最稳妥解法是用equals()或拆箱比较;==比较的是对象地址而非数值,Integer缓存仅对-128~127间valueOf()创建的对象生效,new Integer()总新建对象,超范围或手动创建时==不可靠。

直接用 equals() 或先转成基本类型再比较,是最稳妥的解法。缓存机制本身不是 bug,而是 JVM 的性能优化设计;真正的问题在于误把引用比较当数值比较用。
理解 == 在 Integer 场景下到底在比什么
== 比较的是两个变量是否指向堆中同一个对象地址,不是数值是否相等。而 Integer 缓存池只对 经由 Integer.valueOf() 创建的对象 生效——自动装箱(如 Integer a = 127;)就走 valueOf,但 new Integer(127) 绕过缓存,每次新建对象。
- -128 到 127 范围内:多次赋值相同值 → 复用缓存池中同一对象 → == 返回 true
- 128 及以上(或 -129 及以下):每次调用 valueOf → 新建对象 → == 返回 false
- new Integer(x):无论 x 是多少,都创建新对象 → 和任何缓存对象 == 都为 false
实战中高频踩坑场景与写法对照
这些写法看着相似,行为却完全不同:
- Integer a = 127, b = 127; → a == b 为 true(同缓存对象)
- Integer c = 128, d = 128; → c == d 为 false(两个独立对象)
- Integer e = new Integer(127), f = Integer.valueOf(127); → e == f 为 false(一个新对象,一个缓存对象)
- Integer g = 128; int h = 128; → g == h 为 true(g 自动拆箱成 int 后数值比较)
安全可靠的替代方案
不依赖缓存范围,也不受对象创建方式影响:
- 统一用 g.equals(h):适用于所有 Integer 间比较,内部已做 null 安全和类型校验
- 显式拆箱后比较:g.intValue() == h.intValue() 或直接 g == h.intValue()(推荐用于确定非 null 场景)
- 集合键值使用时特别注意:HashMap
中 key 用 128 两次,会生成两个不同 key,导致重复插入 —— 这类问题必须靠 equals/hashCode 保证语义正确性,不能靠 ==
进阶控制:按需扩大缓存范围(慎用)
若业务大量使用固定区间(如订单号 0~200),可通过 JVM 参数临时扩展缓存上限:
- 启动参数:-Djava.lang.Integer.IntegerCache.high=200
- 效果:valueOf(180) 开始复用缓存,== 在该范围内可能再次为 true
- 注意:缓存对象在类加载时即常驻堆内存,增大 high 值会多占约 (200 + 128) × 对象大小,低配环境易引发 OOM

















