Java中Integer的缓存池是怎么实现的?
开始介绍之前,希望大家能想一想下面这串代码运行出来的结果是什么?
public class IntegerCacheTest {
public static void main(String[] args) {
fun1();
fun2();
fun3();
fun4();
}
public static void fun1(){
Integer num1 = -129;
Integer num2 = -129;
System.out.println(num1 == num2);
}
public static void fun2(){
Integer num1 = -128;
Integer num2 = -128;
System.out.println(num1 == num2);
}
public static void fun3(){
Integer num1 = 127;
Integer num2 = 127;
System.out.println(num1 == num2);
}
public static void fun4(){
Integer num1 = 128;
Integer num2 = 128;
System.out.println(num1 == num2);
}
}
-129和-129的Integer对象,相不相等?使用基本数据类型int定义的值肯定相等,但是Integer是引用数据类型,而且-129不在缓存区里,所以应该是false。
-128在不在缓存区呢?把它和127,128一块测试,效果如下:
false
true
true
false
从结果上看,说明128也并不在Integer的缓存区里。所以Integer的缓存范围是-128到127之间,并且包含两个边界值,一共256个数(别忘了有个0)。
下面对Integer的相关源码解析一下:
上面的代码Integer在创建对象时会使用到valueOf方法,下面来看一下这个方法:
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们可以发现当i在满足IntegerCache.low和i <= IntegerCache.high的时候直接返回一个IntegerCache里缓存的数据,而不满足的条件则是直接new一个新的Integer。
下面查看一下IntegerCache的源码:
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* jdk.internal.misc.VM class.
*
* WARNING: The cache is archived with CDS and reloaded from the shared
* archive at runtime. The archived cache (Integer[]) and Integer objects
* reside in the closed archive heap regions. Care should be taken when
* changing the implementation and the cache array should not be assigned
* with new Integer object(s) after initialization.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
CDS.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
可以看到low是-128,high虽然并没有在定义的时候赋值,但是执行静态代码块的时候把127赋值给了high,这就是缓存的数据范围。通过代码分析,可以看到**static final Integer[] cache;**保存了从-128到127的数据,所以我们创建Integer对象时如果在这个区间,其实使用的都是缓存对象,所以使用==判断是true,反之为false,这边使用的是设计模式中的享元模式。