java自动装箱拆箱的核心陷阱是隐式执行时机与null安全性,拆箱遇null必抛npe;比较用equals而非==;泛型集合避免隐式装拆箱;优先valueof而非new;兜底判空用objects.requirenonnullelse或三元运算。

Java 面试中一问就错的自动装箱与拆箱,核心陷阱不在“会不会用”,而在“什么时候悄悄执行、执行时是否安全”。真正拉开差距的,是能否一眼识别高危场景并给出可落地的规避方式。
拆箱前必须判空,null 是唯一必炸点
自动拆箱本质是调用 xxxValue() 方法(如 intValue()、booleanValue()),而 null 无法响应任何实例方法调用——这是所有 NPE 的根源。常见爆炸现场包括:
-
Integer a = null; int b = a;→ 直接抛NullPointerException -
Boolean flag = null; if (flag) { }→ 拆箱发生在条件求值前 -
Map<string integer> map = new HashMap(); int v = map.get("missing");</string>→get()返回 null,赋值即炸 -
for (Integer num : list) { sum += num; }→ list 中含 null,第一轮就崩
正确做法:不依赖“运气”,主动兜底。优先用 Objects.requireNonNullElse()(Java 9+)或三元判空:
int value = Objects.requireNonNullElse(num, 0);int value = (num != null) ? num : 0;
比较包装类永远不用 ==,一律走 equals 或 Objects.equals
== 比较的是引用地址,不是数值。Integer 在 -128 到 127 范围内复用缓存对象,所以 Integer a = 100; Integer b = 100; a == b 返回 true;但 Integer c = 200; Integer d = 200; c == d 就是 false——逻辑完全不可控。
更危险的是,Objects.equals(a, b) 内部已处理 null 安全,比 a != null && a.equals(b) 更简洁可靠:
集合与泛型中避免隐式装箱/拆箱高频开销
泛型擦除导致每次 add(int) 必装箱、每次 get() 后赋给 int 必拆箱。在循环或大数据量场景下,会生成大量短命对象,加重 GC 压力。
- 性能敏感路径(如实时计算、日志计数)改用 基本类型数组(
int[])或专用库(Eclipse Collections 的IntList) - Stream 处理 List
时,显式调用 .mapToInt(Integer::intValue),避免.mapToInt(i -> i)触发二次自动拆箱 - 数据库映射字段(如 MyBatis)用
COALESCE(col, 0)或实体字段加默认值,从源头减少 null 入库
手动控制装箱来源,拒绝 new + 优先用 valueOf
虽然 Integer i = 100; 看似简单,但它背后是 Integer.valueOf(100),利用了缓存;而 new Integer(100) 绕过缓存、强制新建对象(JDK 9 已废弃)。第三方工具或旧框架可能隐式调用构造器,带来隐蔽性能损耗。
统一规范写法:
Integer num = Integer.valueOf(123);Boolean flag = Boolean.valueOf(true);
对自定义封装或跨模块传入的包装类,不假设其来自缓存,尤其在做 == 判断或身份校验时保持警惕。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











