反编译可揭示自动装箱与拆箱本质:integer a = 100 编译为 integer.valueof(100),int b = a 编译为 a.intvalue(),算术运算需先拆箱后装箱;-128~127 使用缓存,null 拆箱触发 nullpointerexception。

反编译是看清自动装箱与拆箱本质最直接的方式——它能让你看到编译器到底干了什么,而不是只停留在“语法糖”的模糊印象上。
反编译前先写个典型样例
准备一段包含装箱和拆箱的简洁代码:
// TestBoxing.java
public class TestBoxing {
public static void main(String[] args) {
Integer a = 100; // 自动装箱
int b = a; // 自动拆箱
Integer c = b + 5; // 先拆箱(b→int),再装箱(int→Integer)
}
}
用 javap 查看字节码关键行
编译后执行:javap -c TestBoxing,重点关注 main 方法的字节码输出。你会看到类似以下核心指令:
-
iconst_100 → invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
这说明Integer a = 100;实际被编译为Integer.valueOf(100),不是 new Integer(100) -
aload_1 → invokevirtual #22 // Method java/lang/Integer.intValue:()I
这说明int b = a;实际调用的是a.intValue() -
iload_2 → iconst_5 → iadd → invokestatic #16 // Integer.valueOf(I)
加法运算中,包装类参与算术操作时,必须先拆箱;结果赋给 Integer 变量时,又触发装箱
重点观察缓存机制的字节码痕迹
把数值换成 Integer x = 127; 和 Integer y = 128;,再反编译对比:
- 对 -128 到 127 范围内的 int 值,
valueOf()会从IntegerCache.cache[]返回已有对象——字节码里仍是invokestatic Integer.valueOf,但运行时行为不同 - 而
new Integer(127)(已过时)会生成new指令和构造方法调用,字节码明显不同,可作对照验证 - 这种差异在反编译结果里不直接显示,但结合源码(如 Integer.valueOf 源码)和运行时
==对比就能印证
警惕空指针在字节码中的“隐身”风险
写一个可能为 null 的拆箱场景:
Integer n = null;
int m = n; // 这里会触发 NullPointerException
反编译后你会发现:这一行仍被转成 n.intValue()。但 JVM 在执行该指令时,发现 n 是 null,就抛出异常——也就是说,空指针不是装箱拆箱本身的问题,而是拆箱动作对 null 引用的必然响应。字节码不会加判空,风险完全由开发者承担。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











