javap -c 可清晰查看自动装箱拆箱的字节码:装箱转为 integer.valueof() 调用,拆箱转为 intvalue() 调用;集合操作含隐式装拆箱;== 比较依赖缓存范围(-128~127),字节码相同但运行结果不同。

直接用 javap -c 查看编译后的字节码,就能清晰看到自动装箱和拆箱被编译器展开成了哪些具体方法调用。这不是 JVM 运行时行为,而是编译阶段插入的固定逻辑。
装箱对应 valueOf() 调用
当写 Integer i = 100;,编译器会转成 Integer.valueOf(100),字节码中表现为:
-
bipush 100或iconst_100:把整数压入操作数栈 -
invokestatic java/lang/Integer.valueOf:(I)Ljava/lang/Integer;:调用静态工厂方法
注意:-128 到 127 的整数会命中缓存,超出范围则新建对象,但字节码指令完全一样,区别在 valueOf 方法内部实现。
拆箱对应 xxxValue() 调用
当写 int x = i;(i 是 Integer),字节码实际是:
-
aload_1:加载引用 i 到栈顶 -
invokevirtual java/lang/Integer.intValue:()I:调用实例方法取基本值 -
istore_2:把返回的 int 存入局部变量 x
若此时 i 为 null,运行时就会抛 NullPointerException——因为 invokevirtual 在空引用上调用会失败。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
集合操作中的隐式转换也很典型
比如 list.add(3.14f)(list 是 List<float></float>):
-
fconst_2或ldc加载浮点常量 -
invokestatic java/lang/Float.valueOf:(F)Ljava/lang/Float;→ 装箱 invokeinterface java/util/List.add:(Ljava/lang/Object;)Z
而 float f = list.get(0) 则包含 checkcast java/lang/Float + invokevirtual floatValue 两步,即先类型校验再拆箱。
用 == 比较时的陷阱在字节码里一目了然
Integer a = 100, b = 100; System.out.println(a == b); 的字节码中:
- 两次
invokestatic Integer.valueOf都指向同一缓存对象 -
if_acmpeq指令直接比较两个引用地址
换成 a = 200; b = 200;,虽然指令完全相同,但 valueOf 返回的是两个不同对象,== 自然为 false。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










