
Integer.valueOf() 什么时候走缓存,什么时候 new 对象
Java 的 Integer.valueOf() 不是每次都创建新对象,它内部维护了一个 [-128, 127] 的缓存池(默认范围),在这个区间内返回的是缓存中的同一个 Integer 实例;超出这个范围,每次调用都会 new 一个新对象。
这直接影响 == 判断结果:缓存内的值用 == 可能为 true,跨范围则一定为 false —— 很多人踩坑就在这里。
- 缓存范围由 JVM 参数
-Djava.lang.Integer.IntegerCache.high=xxx可调(仅上限可设,下限固定为 -128) - 缓存初始化发生在
Integer类首次主动使用时,不是启动时就加载 -
new Integer(100)永远不走缓存,不管值多少,都新建对象 - 编译器对字面量的自动装箱(如
Integer a = 100;)等价于Integer.valueOf(100),会走缓存
为什么 == 比较 Integer 有时 true 有时 false
根本原因在于你比较的是引用,不是值。当两个 Integer 都来自缓存(比如都在 [-128, 127] 内),它们指向同一个对象,== 返回 true;只要有一个不在缓存里,或者用了 new,== 就是 false。
常见错误现象:Integer a = 127; Integer b = 127; System.out.println(a == b); // true,但把 127 换成 128 就变成 false。
立即学习“Java免费学习笔记(深入)”;
citySHOP是一款集CMS、网店、商品、分类信息、论坛等为一体的城市多用户商城系统,已完美整合目前流行的Discuz! 6.0论坛,采用最新的5.0版PHP+MYSQL技术。面向对象的数据库连接机制,缓存及80%静态化处理,使它能最大程度减轻服务器负担,为您节约建设成本。多级店铺区分及联盟商户地图标注,实体店与虚拟完美结合。个性化的店铺系统,会员后台一体化管理。后台登陆初始网站密匙:LOVES
- 永远别用
==比较包装类的值相等,该用.equals() -
.equals()在参数为 null 时会 NPE,而Objects.equals(a, b)更安全 - 注意:
Integer.valueOf(null)会抛NullPointerException,不是缓存问题,是参数校验失败
valueOf 缓存和自动装箱、拆箱的关系
自动装箱(boxing)如 Integer i = 100; 底层就是调 Integer.valueOf(100);自动拆箱(unboxing)如 int j = i; 是调 i.intValue(),和缓存无关。
所以缓存只影响装箱行为,不影响拆箱逻辑或数值计算。但一旦你混用缓存对象和 new 出的对象做 ==,问题就藏不住了。
- 泛型集合(如
ArrayList<integer></integer>)add 的时候会自动装箱,走valueOf(),因此小整数反复 add 不会爆炸式创建对象 - 反射或序列化反序列化后的
Integer不来自缓存池,即使值在范围内,==也必为 false - JSON 库(如 Jackson)反序列化出的
Integer默认也是 new 出来的,不受缓存控制
缓存机制对性能和内存的实际影响
缓存本身开销极小:一个长度为 256 的 Integer[] 数组,加上静态初始化逻辑,几乎可以忽略。但它能显著减少小整数对象的 GC 压力——尤其在高频装箱场景(如循环计数、Map 键值)中。
不过别指望靠它优化业务逻辑。它的存在是为了语义一致性(JLS 规定小整数装箱必须复用),不是给你手动管理对象生命周期用的。
- 不要为了“省对象”刻意把业务值卡在 127 以内;逻辑正确比省几个字节重要得多
- 高并发下缓存数组是共享且不可变的,线程安全,无需额外同步
- 如果真需要更大范围的缓存(比如高频用到 0~1000),自己建
Map<integer integer></integer>池更可控,也更明确
缓存边界是隐形契约,不是 API 承诺——JDK 只保证 [-128, 127] 必缓存,不保证更高范围一定不缓存(虽然目前实现没扩展)。依赖具体缓存范围写逻辑,等于把代码绑死在某个 JDK 实现细节上。









