Java包装类中Boolean、Byte、Character(\u0000–\u007f)、Short、Integer(-128~127)和Long(-128~127)有缓存,Integer缓存范围可通过JVM参数扩展;推荐用valueOf而非new以复用对象、减少GC;比较值时必须用equals(),避免==导致的对象池陷阱。

Java 中包装类的 valueOf 方法确实会缓存部分小整数、布尔值等,合理使用能避免重复创建对象,提升性能;但盲目依赖缓存范围或误用 == 比较,反而会掉进对象池陷阱。
哪些包装类有缓存?缓存范围是多少?
不是所有包装类都缓存,也不是所有数值都被缓存。JDK 规范只强制要求 Boolean、Byte、Character(\u0000–\u007f)、Short、Integer(-128 到 127)和 Long(-128 到 127)在特定范围内复用对象。其中 Integer 的缓存范围可通过 JVM 参数 -Djava.lang.Integer.IntegerCache.high=xxx 扩展,但默认就是 -128~127。
-
Boolean.valueOf(true)总是返回同一个TRUE实例 -
Integer.valueOf(100)返回缓存对象;Integer.valueOf(200)每次新建对象 -
Double.valueOf(1.0)和Float.valueOf(1.0f)不缓存(JDK 规范未要求)
为什么推荐用 valueOf 而不是 new?
new Integer(100) 每次都新建堆对象,而 Integer.valueOf(100) 在缓存范围内直接复用已有实例,减少 GC 压力,也更符合“享元”设计思想。尤其在循环、集合装箱、频繁转换场景下效果明显。
- 集合操作:
List底层调用的是list = Arrays.asList(1, 2, 3); Integer.valueOf(),不是new - 手动装箱时写
Integer i = Integer.valueOf(42);比Integer i = new Integer(42);更安全高效 - 自动装箱(如
Integer i = 42;)编译后也转为valueOf,但仅限字面量或编译期常量
对象池陷阱:== 比较失效的典型场景
缓存让同一数值的多个 valueOf 调用返回相同引用,于是有人用 == 比较包装类——这在缓存范围内“碰巧”成立,但超出范围就崩。这是最常见也最隐蔽的对象池陷阱。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- ✅
Integer a = Integer.valueOf(100); Integer b = Integer.valueOf(100); a == b→ true(同引用) - ❌
Integer a = Integer.valueOf(200); Integer b = Integer.valueOf(200); a == b→ false(不同对象) - ⚠️ 即使是
Integer a = 100; Integer b = 100; a == b也依赖编译器优化和缓存,不可靠 - ✔️ 正确做法永远用
equals()比较值:a.equals(b),它会先判空再比数值
实际建议:何时关注、何时忽略
日常开发中不必刻意记忆缓存边界,但需建立两个习惯:
- 统一用
valueOf()替代new构造器(IDE 通常会警告new Integer(x)已废弃) - 所有包装类比较一律用
equals(),绝不依赖==判等 - 性能敏感场景(如高频数值计算、大量 DTO 装箱)可考虑预热缓存(如提前调用
Integer.valueOf(127)),但收益有限,优先优化算法 - 自定义类型若需类似对象池,应显式设计并文档化,不要模仿包装类的“隐式”行为
不复杂但容易忽略:缓存是优化手段,不是语义保证;对象复用带来便利,也悄悄改写了引用相等的直觉。守住 valueOf + equals 这两条线,就能避开绝大多数坑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










