问题:
Java的Integer类内部实现了一个静态缓存池,用于存储特定范围内的整数值对应的Integer对象。默认情况下,这个范围是-128至127。当通过lnteger.valueOf(int)方法创建一个在这个范围内的整数对象时,并不会每次都生成新的对象实例,而是复用缓存中的现有对象,会直接从内存中取出,不需要新建个对象。
实践:
java
public class Test {
public static void main(String[] args) {
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(1);
System.out.println(a==b);;
}
}

源码:
java
private static class IntegerCache {
//整体的思路就是
//1.valueof或者自动装箱调用该类的静态代码块
//2.可以通过jvm设定最大值,也可以不设定
//3.设定好最大值,计算范围,生成新的数组赋值给归档文件,
//4.最后再赋值给cache缓存
//缓存的下界,默认值为 -128,固定不可修改
static final int low = -128;
//缓存的上界,默认值为 127,但可以通过 JVM 参数动态调整
//java -Djava.lang.Integer.IntegerCache.high
static final int high;
//缓存数组,存储从 low 到 high 范围
//这个数组就是缓存机制的核心
static final Integer[] cache;
//一个额外的缓存数组,用于支持 Java 的 Class Data Sharing (CDS) 功能。
//CDS 是一种优化技术,允许将共享的类数据(如缓存池)保存到归档文件中,从而加速 JVM 启动。
//archivedCache就是归档缓存
static Integer[] archivedCache;
//静态代码块在类加载时执行,负责初始化缓存池。
//IntegerCache 的 static 块会在第一次调用 Integer.valueOf(int) 或使用自动装箱时触发,也就说会触发缓存池
static {
// high value may be configured by property
// 上界可以通过配置这个属性
int h = 127;//此时配置的上界是127
//你可以通过java -Djava.lang.Integer.IntegerCache.high=设置最高值
//java -Djava.lang.Integer.IntegerCache.high=256里设置为256
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
//integerCacheHighPropValue 就是你设置的值
//如果integerCacheHighPropValue不为空
if (integerCacheHighPropValue != null) {
try {
//1.integerCacheHighPropValue转换成int值
//2.比较 默认的127的和你设置的值,取最大
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
/
/*
Integer.MAX_VALUE 是 Java 中 int 类型的最大值,等于 2^31 - 1,即 2147483647。它表示 int 类型能够存储的最大正整数。
low 是缓存池的下界,默认值为 -128。
(-low) 表示下界的绝对值,即 128。
Integer.MAX_VALUE - (-low)
这部分计算了从 low 到 Integer.MAX_VALUE 的整数个数。
公式:Integer.MAX_VALUE - (-low) 等价于 Integer.MAX_VALUE + low。
Integer.MAX_VALUE - (-low) - 1
减去 1 是为了确保数组的长度不会超出 Integer.MAX_VALUE。
数组的长度由 (high - low) + 1 决定,因此需要限制 high 的最大值。
*/
//这个就是保证h在合法int范围内
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
//如果这个属性不能被解析为整数,忽略它
}
}
//赋值给high
high = h;
// Load IntegerCache.archivedCache from archive, if possible
//从归档文件中加载缓存,如果存在的话
CDS.initializeFromArchive(IntegerCache.class);
// 计算容量
// high - low = 127 - (-128) = 255
// + 1是因为要算上边界
// eg.6 - 1 = 5, 但是之间这是之间差5个数
// 如果 把左边界1算上,那就是 1 2 3 4 5
// 那还少一个6,所以要加1
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
//从归档文件里查找如果没有该缓存或者是所需容量的size>大于缓存的长度
//就创建一个新的数组
if (archivedCache == null || size > archivedCache.length) {
//创一个size大小的数组
Integer[] c = new Integer[size];
//j=-128
int j = low;
//-128一直自增到c.length 也就是256
//但是是加到255就停止,因为i < c.length而不是等于 i < 256
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
//把新生成的数组给归档文件
archivedCache = c;
}
//再给cache,到这里就完成了缓存
cache = archivedCache;
//确保IntegerCache.high的值至少为127,即保证了缓存至少包含从-128到127的所有整数值,确保合理范围
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
//这是一个静态类,不需要实例化,所以需要私有
private IntegerCache() {}
}
归档文件
归档文件是一个特殊的文件,通常命名为 classes.jsa
(Java Shared Archive),用于存储以下内容:
- 类元数据:如类的结构信息。
- 常量池:如字符串常量、方法引用等。
- 缓存池 :如
IntegerCache
的缓存数组。
它的主要目的是:
- 加速 JVM 启动:通过预加载常用类的数据,减少类加载的时间。
- 节省内存:多个 JVM 实例可以共享同一个归档文件,避免重复加载相同的类数据。
归档文件的内容
归档文件中存储了以下类型的数据:
(1) 类元数据
- 类的结构信息,包括类的字段、方法、继承关系等。
- 这些数据在 JVM 加载类时会被直接使用,避免重新解析
.class
文件。
(2) 常量池
- 常量池中存储了类中的常量数据,例如:
- 字符串常量(如
"Hello"
)。 - 方法引用、字段引用等符号引用。
- 字符串常量(如
- 这些数据可以直接从归档文件中读取,而无需重新解析。
(3) 缓存池
- 某些类(如
IntegerCache
)的缓存数据也会被存储到归档文件中。 - 例如,
IntegerCache
的缓存数组(archivedCache
)可以从归档文件中加载,避免每次运行时重新创建。