title: 包装类的缓存机制
date: 2019-02-28 21:50:12
tags: Java基础
包装类的缓存机制与valueOf()
引言
Java有8种基本类型,每种都有一个包装类型,有很多静态方法、变量等,方便对数据进行操作。包装类可以由valueOf()
静态方法去创建,也可以用new关键字去创建实例对象,但为什么推荐使用valueOf()
来创建呢。
首先,我们来看一个例子:
public class Test {
public static void main(String[] args) {
Integer a = 1;
Integer b = 1;
Integer c = 128;
Integer d = 128;
if(a == b){
System.out.println("a与b相同");
}
if(c == d){
System.out.println("c与d相同");
}
}
}
运行结果
a与b相同 c与d不相同
分析
这段代码创建了4个
Integer
类型的对象实例a、b、c、d,照常理来说,4个对象,其引用地址不同,此例子的输出应该都为不相同,但结果确是a与b相同,c与d不同,这是为什么?
此处我们是采用自动装箱的方式来创建的Integer
对象,而这相当于调用了valueOf()
的方法,所以就得从valueOf()
这个静态方法说起。
###valueof的分析
首先,看看Integer
的valueOf()
方法的源码
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
这个表达式,就通过new来得到对象,如果满足呢?
再来看看IntegerCache类,IntegCache类是Integer类的一个内部静态类,其源码如下。
/**
* 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
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
分析
首先,从Javadoc中看出这个类是用来实现缓存的。它定义了三个静态参数,缓存数组
cache
,数组最小值low
,赋值为-128以及数组最大值high
,最大值映射到了"java.lang.Integer.IntegerCache.high"
上。
,并支持 -128 到 127 之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改。
修改jvm参数后
运行结果
a与b相同 c与d不相同
结论
IntegerCache
这个Integer
私有静态类代表Integer
缓存,它在被首次主动使用时,会被初始化,static代码块中的会被执行,通过一个 for
循环创建出一个值为-128~127的一个缓存数组cache
,以后,如果创建的值在low
和high
之间,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。这种机制使我们可以根据应用程序的实际情况灵活地调整来提高性能。是什么原因选择这个 -128 到 127 这个范围呢?因为这个范围的整数值是使用最广泛的,通过使用共享对象,就可以节省内存空间了。在程序中第一次使用 Integer
的时候也需要一定的额外时间来初始化这个缓存。这种机制在其他包装类中也有类似的实现。这种缓存策略也是一种设计模式,叫做享元模式。