Java自动装箱调用valueOf()(含缓存优化),拆箱调用xxxValue();null拆箱抛NPE;==比较包装类是比地址,缓存区间内才相等;泛型集合频繁装拆箱影响性能。

Java 中基本数据类型和包装类之间的自动转换,表面看只是赋值或运算时的语法糖,实则背后有一套明确的编译规则与运行时行为。理解它不靠死记,而在于抓住“谁在什么时候调用了什么方法”。
自动装箱:本质是调用 valueOf()
当你写 Integer i = 100;,编译器不会生成 new Integer(100),而是替换成 Integer.valueOf(100)。同理:
- Boolean b = true; → 编译为 Boolean.valueOf(true)
- Double d = 3.14; → 编译为 Double.valueOf(3.14)
- Character c = 'A'; → 编译为 Character.valueOf('A')
valueOf() 方法内部做了缓存优化:Integer、Byte、Short、Character(0–127)、Boolean(true/false)在常用范围内复用对象;超出范围(如 Integer.valueOf(200))则新建实例。Long 和 Float 的缓存策略较弱,JDK 8 后默认只缓存 -128~127,且 Long 缓存上限可通过 JVM 参数调整。
自动拆箱:本质是调用 xxxValue()
当你写 int x = i;(i 是 Integer 类型),编译器实际插入的是 i.intValue()。其他类型同理:
- boolean flag = b; → b.booleanValue()
- double v = d; → d.doubleValue()
- char ch = c; → c.charValue()
关键风险就在这里:如果 i 是 null,调用 intValue() 就会抛出 NullPointerException。这不是编译错误,而是运行时崩溃,常见于 Map.get()、JSON 解析、数据库字段为 NULL 的场景。
== 比较陷阱:缓存影响引用判断
因为 valueOf() 可能返回缓存对象,所以:
- Integer a = 100, b = 100; → a == b 为 true(都在 -128~127 缓存区间)
- Integer c = 200, d = 200; → c == d 为 false(各自新建对象,地址不同)
- 但 a.equals(b) 和 c.equals(d) 都为 true(比较的是数值)
记住:对包装类用 == 判断相等,本质上是在比对象地址,不是比值——除非你明确知道它们来自缓存且范围安全。
泛型与集合是装箱/拆箱最频繁的场景
List
- list.add(42); → 自动装箱为 Integer.valueOf(42)
- int n = list.get(0); → 自动拆箱为 list.get(0).intValue()
循环中反复 add 或 get,等于反复创建/销毁包装对象,可能引发 GC 压力。高频计算或大数据量场景下,优先考虑原生数组(int[])或第三方库(如 Eclipse Collections、Trove)提供的原始类型集合。


















