核心一句话:Java 的
Integer
类通过IntegerCache
实现了对 -128 到 127 范围内的整数的自动缓存,以提升性能和节省内存,这是 Java 自动装箱(autoboxing)机制中的关键优化。
一、什么是 Integer
缓存机制?
Java 在 Integer
类中内置了一个静态内部类 IntegerCache
,它预先创建并缓存了 一定范围内的 Integer
对象(默认是 -128 到 127),当使用自动装箱或 Integer.valueOf(int)
创建 Integer
时,如果值在这个范围内,直接返回缓存中的对象,而不是新建一个。
✅ 示例说明:
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(同一个缓存对象)
Integer x = 200;
Integer y = 200;
System.out.println(x == b); // false(超出缓存范围,新建对象)
二、设计目的(Why?)
目的 | 说明 |
---|---|
性能优化 | 避免频繁创建小整数对象,减少 GC 压力 |
内存节省 | 共享常用整数对象,减少重复实例 |
提高装箱效率 | Integer.valueOf() 比 new Integer() 更高效 |
符合使用习惯 | 小整数(如循环变量、状态码)使用频率极高 |
💡 这是典型的“享元模式”(Flyweight Pattern)应用。
三、实现原理
1. 核心方法:Integer.valueOf(int i)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
- 这是自动装箱背后调用的方法(如
Integer a = 100;
实际调用valueOf(100)
)。 - 如果
i
在缓存范围内,返回缓存数组中的对象。 - 否则,新建一个
Integer
对象。
⚠️ 注意:
new Integer(100)
不会走缓存,始终创建新对象!
2. 缓存类:IntegerCache
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// 可通过 JVM 参数 -Djava.lang.Integer.IntegerCache.high=xxx 调整 high
int h = 127;
String integerCacheHighProp = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighProp != null) {
try {
int i = parseInt(integerCacheHighProp);
i = Math.max(i, 127); // 至少 127
h = Math.min(i, 2147483647); // 最大 int
} catch (NumberFormatException e) {}
}
high = h;
// 创建缓存数组
cache = new Integer[(high - low) + 1];
int j = low;
for (int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 强引用,防止被 GC
assert IntegerCache.high >= 127;
}
}
✅ 关键点:
low
固定为-128
high
默认127
,但可通过-Djava.lang.Integer.IntegerCache.high=255
修改- 缓存数组在类加载时初始化,JVM 全局唯一
- 使用
static final
数组,保证线程安全
四、示例代码
✅ 示例 1:验证缓存机制
// 在缓存范围内
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true
System.out.println(a.equals(b)); // true
// 超出缓存范围
Integer x = 200;
Integer y = 200;
System.out.println(x == y); // false
System.out.println(x.equals(y)); // true
// 使用 new(不走缓存)
Integer m = new Integer(100);
Integer n = new Integer(100);
System.out.println(m == n); // false
System.out.println(m.equals(n)); // true
✅ 示例 2:使用 valueOf
显式调用缓存
Integer c = Integer.valueOf(50); // 走缓存
Integer d = Integer.valueOf(50); // 同一个对象
System.out.println(c == d); // true
✅ 示例 3:修改缓存上限(JVM 参数)
java -Djava.lang.Integer.IntegerCache.high=500 MyApp
Integer huge = 400;
Integer another = 400;
System.out.println(huge == another); // true(如果 high >= 400)
⚠️ 注意:修改缓存范围会增加 JVM 启动时的内存占用。
五、缓存范围(默认)
范围 | 是否缓存 | 说明 |
---|---|---|
-128 到 127 |
✅ 是 | 默认缓存范围 |
< -128 或 > 127 |
❌ 否 | 每次 valueOf 或装箱都创建新对象 |
💡 其他包装类也有类似缓存:
Byte
:-128 ~ 127(全范围)Short
:-128 ~ 127Long
:-128 ~ 127Character
:0 ~ 127(ASCII)Boolean
:TRUE
/FALSE
两个常量
六、常见错误与陷阱 ❌
❌ 错误 1:用 ==
比较 Integer
值
Integer a = 200;
Integer b = 200;
if (a == b) { ... } // ❌ 可能在某些 JVM 下为 false
✅ 正确做法:使用
.equals()
if (a.equals(b)) { ... } // ✅ 安全
// 或
if (Objects.equals(a, b)) { ... } // 更安全(支持 null)
❌ 错误 2:误以为 new Integer()
走缓存
Integer x = new Integer(100);
Integer y = 100;
System.out.println(x == y); // false!x 是新对象
七、注意事项 ⚠️
注意点 | 说明 |
---|---|
✅ 缓存是 JVM 全局的 | 所有类共享同一份缓存 |
⚠️ 只对 valueOf 和自动装箱有效 |
new Integer() 不走缓存 |
⚠️ 可配置上限 | 通过 -Djava.lang.Integer.IntegerCache.high=N |
✅ 线程安全 | 缓存数组是 static final ,初始化后不可变 |
⚠️ 增加 high 会增加内存 | 每多一个缓存数,多一个 Integer 对象 |
✅ -128 不可修改 | low 固定为 -128 |
八、最佳实践 ✅
1. 使用 Integer.valueOf()
而非 new Integer()
// ❌ 不推荐
Integer num = new Integer(100);
// ✅ 推荐
Integer num = Integer.valueOf(100); // 可能走缓存
2. 比较 Integer
用 equals()
或 Objects.equals()
// ❌ 危险
if (a == b)
// ✅ 安全
if (a.equals(b))
if (Objects.equals(a, b)) // 更好,支持 null
3. 在性能敏感场景复用缓存对象
// 循环中使用小整数,自动复用缓存
for (int i = 0; i < 100; i++) {
list.add(i); // 自动装箱,可能复用缓存对象
}
4. 合理设置缓存大小(如高频使用大整数)
# 如果应用常使用 0~500 的整数
java -Djava.lang.Integer.IntegerCache.high=500 MyApp
九、性能影响与优化
场景 | 影响 |
---|---|
✅ 小整数频繁装箱 | 性能显著提升(对象复用) |
⚠️ 大整数装箱 | 无缓存,性能与 new 相同 |
⚠️ 修改 high 过大 | 增加 JVM 启动时间和内存占用 |
✅ 缓存命中 | 减少 GC、降低对象创建开销 |
💡 在高并发、高频装箱场景(如计数器、状态码),缓存机制可带来显著性能提升。
十、总结:快速掌握要点 ✅
项目 | 内容 |
---|---|
缓存范围 | 默认 -128 到 127 |
触发方式 | Integer.valueOf() 和自动装箱(Integer a = 100; ) |
不触发 | new Integer(100) |
可配置 | 通过 -Djava.lang.Integer.IntegerCache.high=N |
实现类 | IntegerCache 静态内部类 |
设计模式 | 享元模式(Flyweight) |
核心目的 | 性能优化、内存节省 |
比较建议 | 使用 .equals() 或 Objects.equals() |
最佳实践 | 用 valueOf ,避免 new ,慎用 == |
🎯 一句话总结:
Java
Integer
缓存机制通过IntegerCache
预先缓存 -128 到 127 的整数对象,使自动装箱和valueOf()
在此范围内复用对象,显著提升性能和内存效率,是 Java 自动装箱的核心优化,使用时应避免==
比较,优先使用equals
。