🦊一句话总结
Integer a = 100;
的完整流程 :
编译期 :Java 编译器将自动装箱转换为Integer.valueOf(100)
的字节码。
运行期 :JVM 执行字节码,调用Integer.valueOf
→ 检查缓存(-128~127)→ 返回缓存对象。
本质:JVM 对高频整数的内存优化,避免重复创建对象。
详细流程拆解
2.1 编译期:语法糖展开
源码
java
Integer a = 100; // Java 语法糖
编译器行为
1、识别自动装箱:
Integer
是包装类型,100
是int
字面量 → 触发自动装箱(Autoboxing)。- 根据 JLS 规范(JLS §5.1.7),必须使用
valueOf
方法。
2、生成字节码:
不生成 new Integer(100)
,而是直接生成 Integer.valueOf(100)
的调用。 如果直接通过 IDEA 查看class文件的源码,有可能看到的代码跟源码一样,反编译器(如 IDEA)会将字节码还原为 Integer a = 100;
,但真实字节码是 valueOf
调用。

这里我们通过命令去查看字节码指令:
java
0: bipush 100 // 将 int 100 压入操作数栈
2: invokestatic #7 // 调用 Integer.valueOf(int)(#7 是常量池索引)
5: astore_1 // 将返回的 Integer 对象存入变量 a
优化:
- 若值超出
bipush
范围(>127),改用sipush
指令。 - 若表达式是常量(如
Integer a = 100 + 28;
),直接折叠为Integer.valueOf(128)
。
java
// java源码
Integer b = 100 + 28;
System.out.println(b);
// IDEA显示 class文件代码
Integer b = 128;
System.out.println(b);
// 字节码指令
sipush 128 // 2字节指令,压入 int 128(>127)
invokestatic #7 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
astore_2
2.2 运行期:JVM 执行
1、字节码执行
1、bipush 100
:将 int
值 100 压入操作数栈。
2、invokestatic Integer.valueOf
:
-
调用
Integer.valueOf(int)
方法。 -
方法内部逻辑:
javapublic static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) { return IntegerCache.cache[i + (-IntegerCache.low)]; // 返回缓存对象 } return new Integer(i); // 超出范围则新建对象 }
3、astore_1
:将返回的 Integer
对象存入局部变量表 slot 1。
2、缓存检查
- 缓存范围 :
-128 ~ 127
(默认上限,可通过-XX:AutoBoxCacheMax=<size>
调整)。 - 命中缓存 :
100
在范围内 → 返回IntegerCache.cache[228]
(同一对象)。 - 未命中缓存 :如
Integer a = 128
→ 创建新对象。
3、缓存初始化
IntegerCache
在类加载时预初始化:
java
static {
Integer[] cache = new Integer[127 - (-128) + 1]; // 256 个元素
for (int i = 0; i < cache.length; i++) {
cache[i] = new Integer(i - 128); // 预创建 -128 ~ 127 的对象
}
}
2.3 对比其他写法
写法 | 底层字节码 | 是否使用缓存 |
---|---|---|
Integer a = 100; |
bipush 100 + invokestatic valueOf |
✅ 是 |
Integer a = new Integer(100); |
new Integer + invokespecial <init> |
❌ 否 |
Integer a = Integer.valueOf(100); |
显式调用 valueOf (同自动装箱) |
✅ 是 |
Integer a = Integer.parseInt("100"); |
返回 int + 自动装箱(同 valueOf ) |
✅ 是 |
关键验证
3.1 缓存命中验证
java
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(同一对象,来自缓存)
3.2 超出缓存验证
java
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(不同对象)
3.3 字节码验证
bash
javap -c Main.class
输出:
java
0: bipush 100
2: invokestatic #7 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
性能优化与建议
优先用 int
替代 Integer
:高频操作(如循环、计算)避免装箱开销。
比较 Integer
值时用 equals
:==
可能因缓存导致意外结果(如 200 == 200
为 false
)。
调整缓存上限 :若业务中大量使用 Integer
(如 0 ~ 1000
),可通过 -XX:AutoBoxCacheMax=1000
扩展缓存。