目录
前言
在 Java 开发中,Integer 作为基本类型 int 的包装类,其对象的创建和内存管理常隐藏着一些“陷阱”。例如,你是否遇到过这样的场景:两个值相同的 Integer 对象,用 == 比较时有时返回 true,有时却返回 false?这种看似矛盾的现象,正是由 Integer 缓存池(Integer Cache) 这一机制引起的。
一、验证Integer缓存池的存在
1.代码验证
Java 的 Integer 类在内存管理中实现了一个缓存池(Cache),用于复用特定范围内的 Integer 对象。通过以下代码可以验证其存在(通过"=="比较变量地址):
代码如下:
public class IntegerTest {
public static void main(String[] args) {
//场景1:值在【-128~+127】范围内(缓存命中)
Integer n1 = 100;
Integer n2 = 100;
System.out.println("场景1:值 100 在缓存范围内,Integer 对象 a 和 b 指向缓存池中的同一对象,因此 == 比较为 true。");
System.out.println(n1 == n2);//内存地址相同输出:ture;反之输出:false
//场景2:值超出【-128~+127】范围(缓存未命中)
Integer n3 = 200;
Integer n4 = 200;
System.out.println("场景2:值 200 超出默认缓存范围,Integer 对象 c 和 d 会创建新的实例,因此 == 比较为 false。");
System.out.println(n3 == n4);//内存地址相同输出:ture;反之输出:false
//场景3;使用new Integer()创建新对象
Integer n5 = 99;
Integer n6 = new Integer(99);
System.out.println("场景3:直接使用 new Integer() 会强制创建新对象,即使值在缓存范围内。");
System.out.println(n3 == n4);//内存地址相同输出:ture;反之输出:false
}
}
2.代码解释
-
场景1:值
100在缓存范围内,Integer对象 n1和 n2 指向缓存池中的同一对象,因此==比较为true。 -
场景2:值
200超出默认缓存范围,Integer对象 n3 和 n4 会创建新的实例,因此==比较为false。 -
场景3:直接使用
new Integer()会强制创建新对象,即使值在缓存范围内。
运行结果如下:

二、Integer缓存池的源码分析
1.缓存池的定义
在 Integer 类的源码中,静态内部类 IntegerCache 负责实现缓存池机制。以下是关键代码片段(基于 OpenJDK 11):
源代码如下(已添加注释):
// Integer 类的静态内部类,用于实现整型对象的缓存池
private static class IntegerCache {
// 缓存的最小值固定为 -128(JLS 规范要求)
static final int low = -128;
// 缓存的最大值(可配置)
static final int high;
// 缓存数组,存储预先创建的 Integer 对象
static final Integer cache[];
static {
// 默认缓存最大值是 127
int h = 127;
// 尝试读取 JVM 参数配置的缓存上限
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
// 解析配置值
int i = Integer.parseInt(integerCacheHighPropValue);
// 确保配置值至少为 127(不能低于默认值)
i = Math.max(i, 127);
// 计算最大允许值:避免数组大小超过 Integer.MAX_VALUE
// (Integer.MAX_VALUE - (-low) -1) 等价于 Integer.MAX_VALUE - 128 + 1
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch (NumberFormatException nfe) {
// 配置值无效时忽略,保持默认值 127
}
}
high = h; // 确定最终的缓存上限
// 初始化缓存数组:容量为 [high - low + 1]
cache = new Integer[(high - low) + 1];
int j = low; // 起始值为 -128
// 遍历填充缓存数组
for (int k = 0; k < cache.length; k++) {
// 创建从 low 到 high 的 Integer 对象
cache[k] = new Integer(j++);
}
// JLS 规范要求必须缓存 [-128, 127] 范围
// 此断言确保 high 至少为 127(防止配置错误)
assert IntegerCache.high >= 127;
}
// 私有化构造方法:禁止外部实例化
private IntegerCache() {}
}
2.关键代码解释
-
缓存范围:默认缓存
-128到127,可通过 JVM 参数-XX:AutoBoxCacheMax=<size>调整上限。 -
静态初始化块:在类加载时预生成缓存对象,存入
Integer[] cache数组。 -
缓存复用:所有在缓存范围内的
Integer对象均从cache数组中复用。
三、Integer.valueOf ()的作用
1.方法定义
Integer.valueOf(int) 是创建 Integer 对象的推荐方式,其实现直接利用了缓存池:
代码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
2.方法行为
-
缓存命中:若值在缓存范围内,直接返回缓存对象。
-
缓存未命中:若值超出范围,创建新对象。
3.方法使用
自动装箱与缓存池
当通过自动装箱(Autoboxing) 创建 Integer 对象时(如 Integer a = 100;),底层实际调用 valueOf() 方法。因此:
Integer a = 100; // 等价于 Integer.valueOf(100)
Integer b = new Integer(100); // 强制创建新对象,绕过缓存
最佳实践
-
优先使用
valueOf():避免不必要的对象创建。 -
避免使用
==比较对象值:应使用equals()或显式拆箱(如intValue())。
总结
Integer 缓存池通过复用频繁使用的小整数对象,显著减少了内存开销和垃圾回收压力。理解其工作机制能帮助开发者编写更高效的代码,同时避免因 == 误用导致的逻辑错误。以上便是本篇文章的全部内容,如有错误请大家指正。
575

被折叠的 条评论
为什么被折叠?



