核心一句话: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 启动时的内存占用。


五、缓存范围(默认)

范围 是否缓存 说明
-128127 ✅ 是 默认缓存范围
< -128> 127 ❌ 否 每次 valueOf 或装箱都创建新对象

💡 其他包装类也有类似缓存:

  • Byte:-128 ~ 127(全范围)
  • Short:-128 ~ 127
  • Long:-128 ~ 127
  • Character:0 ~ 127(ASCII)
  • BooleanTRUE / 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. 比较 Integerequals()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、降低对象创建开销

💡 在高并发、高频装箱场景(如计数器、状态码),缓存机制可带来显著性能提升。


十、总结:快速掌握要点 ✅

项目 内容
缓存范围 默认 -128127
触发方式 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