Integer与int的自动装箱本质是编译器插入Integer.valueOf()(含-128~127缓存),拆箱本质是调用intValue();null拆箱必抛NPE,==比较因引用语义易失效,性能敏感场景应避免自动转换。

Integer 和 int 的正确拆箱与装箱,核心在于理解编译器做了什么、缓存怎么起作用、null 怎么处理,以及什么时候该避免自动转换。
装箱:int → Integer,本质是调用 valueOf()
写 Integer i = 100;,编译器实际生成的是 Integer i = Integer.valueOf(100);。这不是创建新对象的随意操作,而是有缓存策略的:
- -128 到 127(含)范围内的整数,复用
IntegerCache中的已有对象,不新建实例 - 超出该范围(如
Integer j = 3000;),每次都会新建Integer对象 -
Byte、Short、Character(0–127)、Boolean同样有固定缓存;Long缓存上限可配置,Float/Double默认不缓存
拆箱:Integer → int,本质是调用 intValue(),null 是最大风险点
写 int x = i;,运行时执行的是 i.intValue()。一旦 i 是 null,立刻抛 NullPointerException:
- 常见高危场景:从 Map 取值(
map.get("key"))、JSON 解析结果、ORM 查询返回的字段、Optional 未妥善处理 - 三元表达式陷阱:
int v = obj != null ? obj : 0;看似安全,但旧 JDK(如 8u40 之前)仍可能先尝试拆箱obj - 安全写法:
int v = obj == null ? 0 : obj;或int v = Optional.ofNullable(obj).orElse(0);
比较时别踩 == 的坑
== 比较的是引用地址,不是数值:
立即学习“Java免费学习笔记(深入)”;
-
Integer a = 100, b = 100;→a == b为true(同缓存对象) -
Integer c = 200, d = 200;→c == d为false(不同对象) -
Integer e = 100; int f = 100;→e == f为true(e自动拆箱后比值) - 统一用
Objects.equals(a, b)更稳妥,它会先判空再调用equals()
性能敏感场景要绕开自动装箱
高频循环或大数据量处理中,反复装箱会创建大量临时对象,加重 GC 压力:
- 避免在 for 循环里向
List<Integer>大量 add:list.add(i);→ 改用int[]或 Eclipse Collections/Trove 等原始类型集合库 - Stream 计算时,
list.stream().mapToInt(Integer::intValue).sum()比.mapToInt(i -> i).sum()更明确、更安全 - 日志占位符(如
log.info("count: {}", count);)若count是Integer,也会隐式触发装箱,注意参数类型


















