自动装箱与拆箱是基本类型融入面向对象生态的桥梁,但易引发nullpointerexception或缓存陷阱;装箱发生在赋值、传参、集合添加时,调用valueof()(-128~127缓存);拆箱用于运算、比较、赋值,隐式拆箱遇null抛npe;==比较因缓存机制不可靠,应使用objects.equals();高频场景应避免自动装拆箱以提升性能。

自动装箱与拆箱不是“让代码变短”的语法糖,而是让基本类型能自然融入面向对象生态的桥梁——但桥下有坑,踩错一步就掉进 NullPointerException 或缓存陷阱里。
什么时候会触发装箱:赋值、传参、集合添加
装箱发生在编译器发现“基本类型往包装类方向走”时,比如:
-
Integer i = 100;→ 编译器自动转为Integer.valueOf(100) -
list.add(42);(list是ArrayList<integer></integer>)→int被装成Integer才能进集合 -
method(Integer x) { ... }; method(5);→ 实参5自动装箱后传入
注意:valueOf() 不等于构造函数。它对 Integer 的 -128~127 区间复用缓存对象,超出则新建实例——这直接影响 == 比较结果。
什么时候会触发拆箱:运算、比较、赋值给基本类型
拆箱是“包装类往基本类型方向走”,常见于:
-
int x = new Integer(5);→ 编译器插入.intValue() -
if (flag != null && flag)→Boolean对象参与布尔运算,自动拆箱 -
Integer a = 10, b = 20; int sum = a + b;→ 先拆箱再算加法
最危险的是隐式拆箱:Integer a = null; int b = a; 运行时直接抛 NullPointerException,IDE 很难提前预警。
为什么 == 比较在装箱后不可靠
因为装箱结果可能是缓存对象,也可能是新对象:
Integer x = 100, y = 100; System.out.println(x == y); // true(同个缓存对象) <p>Integer m = 200, n = 200; System.out.println(m == n); // false(各自新建对象)</p>
这不是 bug,是设计使然。所有包装类中只有 Byte、Short、Integer、Long、Character 有缓存(范围各异),Float 和 Double 没有。安全做法永远是:Objects.equals(a, b) 或 a != null && a.equals(b)。
高频循环里别依赖自动装拆箱
性能损耗不在单次,而在累积:
for (int i = 0; i → 每次都新建 <code>Integer,GC 压力陡增- Stream 处理
int[]时,Arrays.stream(arr).boxed()是必要开销,但后续.map(i -> i * 2)会反复拆装
真正敏感场景(如金融计算、高频交易),优先用原始类型集合库(如 IntArrayList from HPPC),或手动控制 valueOf() 范围避免意外新建对象。
装箱拆箱真正的复杂点不在“怎么写”,而在于“何时不写”——当变量可能为 null、当比较逻辑混用 == 和 .equals()、当循环体里藏着隐式装箱,问题才开始浮现。










