java自动装箱(int→integer)调用valueof()并缓存-128~127对象,拆箱(integer→int)调用intvalue()易触发npe;==比较包装类为地址比较,缓存外结果不可靠;高频装箱影响性能。

Java 中的自动装箱与拆箱是编译器帮你“悄悄干活”的语法糖,表面写得简洁,背后藏着对象创建、缓存复用和空指针风险。掌握它不靠死记,而在于理解 什么时候发生、怎么发生的、哪里容易出错。
自动装箱:int → Integer 是怎么变的?
当你写下 Integer a = 100;,编译器实际生成的是 Integer a = Integer.valueOf(100);。关键不在“赋值”,而在 valueOf() 的实现逻辑:
- -128 到 127 范围内的整数(含)会从
IntegerCache中返回已缓存的对象,不新建实例 - 超出该范围(如
Integer b = 2000;)每次都会新建Integer对象 -
Byte、Short、Long、Character(0~127)、Boolean同样有类似缓存机制
自动拆箱:Integer → int 看似安全,实则暗藏陷阱
写 int c = a; 看起来只是取个值,但编译后是 int c = a.intValue();。一旦 a 是 null,运行时立刻抛 NullPointerException:
- 常见于从集合中取值未判空:
Integer x = list.get(i); int val = x; // 若 x 为 null,此处崩溃 - 三元表达式易忽略:
int y = flag ? obj.getValue() : 0;—— 若obj.getValue()返回null,拆箱前就已出错 - 方法参数传递时也可能触发,比如接收
Integer参数却直接参与算术运算
等号比较:== 和 equals 的坑全因装箱而起
基本类型用 == 比较值,包装类用 == 比较的是引用地址 —— 这点在缓存范围内会“巧合”成立,一出范围就翻车:
Integer i1 = 100, i2 = 100; System.out.println(i1 == i2); // true(同缓存对象)Integer i3 = 200, i4 = 200; System.out.println(i3 == i4); // false(不同对象)- 统一用
equals()更稳妥,但注意null会导致 NPE,建议用Objects.equals(a, b)
性能敏感场景:别让装箱拖慢你的循环
在高频迭代或大数据量处理中,自动装箱会持续创建临时对象,加重 GC 压力:
- 避免在 for 循环里反复装箱:
for (int i = 0; i - 可改用原始类型集合库(如 Eclipse Collections、Trove)或预分配+手动控制
- 日志拼接、字符串格式化中也常隐式触发装箱(如
log.info("count: {}", count);),注意参数类型
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











