自动装箱和拆箱是编译器语法糖,装箱调用 valueOf()(含缓存优化),拆箱调用 xxxValue();null 拆箱抛 NPE;避免用 == 比较包装类对象。

Java 中的基本类型包装类(如 Integer、Boolean、Double 等)与对应基本类型(int、boolean、double)之间的自动转换,即“自动装箱”(autoboxing)和“自动拆箱”(unboxing),本质上是编译器在语法层面做的糖衣,底层由编译器插入对应的构造方法或 xxxValue() 方法调用,并非 JVM 运行时动态行为。
装箱:基本类型 → 包装类对象
当把一个基本类型值赋给对应包装类引用时(如 Integer i = 100;),编译器会将其重写为调用 Integer.valueOf(int)(而非 new Integer(int))。该方法内部做了缓存优化:对 -128 到 127 范围内的整数,直接返回缓存的 Integer 实例;超出范围则新建对象。
-
Integer.valueOf(100)返回常量池中已存在的对象 -
Integer.valueOf(200)每次都新建Integer实例 - 其他包装类也有类似缓存策略(如
Byte、Short、Character、Long缓存 -128~127;Boolean只有TRUE/FALSE两个实例)
拆箱:包装类对象 → 基本类型
当把包装类引用用于需要基本类型的上下文(如参与算术运算、比较、传参等),编译器插入对应 xxxValue() 方法调用。例如 int x = i;(i 是 Integer)会被转为 i.intValue()。
- 若对象为
null,运行时抛出NullPointerException - 拆箱操作本身不涉及缓存,只做一次方法调用并返回原始值
- 所有包装类的
xxxValue()方法均是 final、无副作用、不可重写
常见陷阱与性能注意点
自动拆装箱虽简化代码,但容易引发隐式空指针、意外对象创建、以及 == 判断逻辑错误等问题。
立即学习“Java免费学习笔记(深入)”;
- 避免用
==比较两个Integer对象:-128~127 范围内可能为 true(因缓存复用),其他范围几乎总为 false - 循环中频繁装箱(如
for (int i = 0; i )会大量创建对象,建议显式使用 <code>Integer.valueOf(i)并控制范围,或改用原始类型集合库(如IntArrayList) - 方法重载时,装箱可能引发意料外的匹配(如
void f(Object)和void f(int)同时存在时,f(1)走int版本,f(i)(i是Integer)却可能走Object版本)
字节码层面的真实表现
通过 javap -c 查看编译后字节码可验证:所有自动拆装箱都被展开为明确的方法调用。
-
Integer i = 100;→iconst_100; invokestatic Integer.valueOf:(I)Ljava/lang/Integer; -
int j = i;→aload_1; invokevirtual Integer.intValue:()I - 没有额外的“运行时转换机制”,JVM 本身不感知“自动”二字,只执行编译器生成的标准方法调用


















