Java包装类缓存机制是JVM为Byte、Short、Integer、Long(-128~127)、Character(0~127)、Boolean(true/false)预先创建并复用对象,仅valueOf()和自动装箱生效,new绕过缓存,==比较引用,equals()比较值。

Java 中基本类型本身没有缓存池,缓存机制只存在于包装类中,核心是 JVM 为常用小数值预先创建并复用对象,避免重复实例化。理解的关键在于:缓存不是针对基本类型值本身,而是针对通过 valueOf()(包括自动装箱)创建的包装类对象。
哪些包装类有缓存?范围分别是多少
并非所有包装类都启用缓存,只有以下五类实现常量池机制:
- Byte、Short、Integer、Long:默认缓存 -128 到 127(含)之间的数值
- Character:缓存 Unicode 值 0 到 127 的字符(即 ASCII 可见字符及控制符)
- Boolean:只缓存 true 和 false 两个实例(全部缓存,无范围限制)
- Float、Double:不提供缓存,每次调用 valueOf() 都新建对象
缓存怎么生效?什么情况下会复用对象
缓存只在调用 valueOf() 方法时触发——而自动装箱(如 Integer i = 100;)底层正是调用 Integer.valueOf(100)。所以:
- 在缓存范围内(如 -128 ≤ x ≤ 127),
Integer.valueOf(x)总是返回同一个对象 - 超出范围(如
Integer.valueOf(200)),每次返回新对象 -
new Integer(x)完全绕过缓存,无论 x 是多少,都创建新对象
为什么 == 比较有时 true、有时 false
== 比较的是对象引用(内存地址),不是数值大小。结果差异直接反映缓存是否命中:
立即学习“Java免费学习笔记(深入)”;
-
Integer a = 100; Integer b = 100;→a == b为 true(同属缓存池,指向同一对象) -
Integer c = 200; Integer d = 200;→c == d为 false(各自新建,地址不同) -
Integer e = new Integer(100); Integer f = 100;→e == f为 false(一个堆中新对象,一个缓存中对象) -
Integer g = 150; int h = 150;→g == h为 true(此时 g 自动拆箱为 int,变成数值比较)
如何安全比较和合理使用缓存
避免因缓存机制导致逻辑错误,关键在写法和设计上保持一致性:
- 对象间数值比较统一用
equals(),它内部已处理 null 和类型校验 - 确定非 null 场景下,可显式拆箱:
a.intValue() == b.intValue() - 若业务高频使用某段区间(如订单状态码 0–199),可通过 JVM 参数扩大 Integer 缓存上限:
-Djava.lang.Integer.IntegerCache.high=199 - 注意缓存对象在类加载时初始化并长期驻留堆内存,盲目调大可能增加 GC 压力或引发 OOM


















