上一篇,我们对Long、Short、Byte三个类的构造方法、内部Cache类以及valueOf进行了分析。 看了文章的人,肯定心中有个疑惑,怎么没有对最为常用的Integer类进行分析? 实际上,正是由于Integer最为常用,JDK源码对其内部缓存实现类 IntegerCache 和 valueOf 方法做了进一步的优化。
我们首先还是来看一段测试代码。
@Test
public void testInteger() {
int primaryInt = 127;
Integer int1 = Integer.valueOf(primaryInt);
Integer int2 = 127;
Assert.assertTrue(int1 == int2);
int1 = new Integer(127);
Assert.assertFalse(int1 == int2);
primaryInt = 128;
int1 = Integer.valueOf(primaryInt);
int2 = 128;
Assert.assertFalse(int1 == int2); // 1
int1 = new Integer(128);
Assert.assertFalse(int1 == int2);
}
复制代码
上述测试代码在不设置JVM参数的情况下,是可以通过测试的。
但是一旦我们在运行该测试的时候设置了JVM参数 -Djava.lang.Integer.IntegerCache.high=255 ,这个测试将在 注析1处失败!下图为IntelliJ IDEA中JVM参数的设置。
这又是为什么呢?
按照我们上一篇的分析,Integer类提供的缓存机制应该也是缓存[-128,127]之间的值。 在不提供 -Djava.lang.Integer.IntegerCache.high=255 JVM参数的时候确实是对的。但是一旦提供了该参数,情况就发生了变化。 变化究竟是怎样的?我们且看Integer的源代码。
我们打开java.lang.Integer的源代码。其中关键性代码如下。
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 =
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() {}
}
复制代码
上面是Integer的内部缓存类 IntegerCache 的源代码,我们发现跟 Long#LongCache 的代码要复杂不少。
IntegerCache 内部还是一样使用的 cache 数组作为缓存数据的机制; IntegerCache 使用了 low 、 high 分别作为缓存的数值的最小值和最大值; low 实际上是一个固定的值 -128 ; high 是可以设置的:
h=127 作为 high 的默认值; VM.getSavedProperty("java.lang.Integer.IntegerCache.high") 获取 java.lang.Integer.IntegerCache.high 参数值视为变量 integerCacheHighPropValue ,并将 该值转换为 int ,然后取127和该转换后的int值中较大的作为变量 i 的值; i , Integer.MAX_VALUE - (-low) -1 中较小的值作为 h 的值;这里之所以取中较小的值,是因为数组size最大为 Integer.MAX_VALUE 。 也就是说数组元素下标最大为 Integer.MAX_VALUE - 1 的。而 IntegerCache 的 cache 数组中需要存放128个负数,所以cache的下标需要再减128也就是 -low , 也就是 Integer.MAX_VALUE - (-low) -1 。 h 再赋值给 high 作为能够缓存的最大整数。 high 之后的代码就是初始化 cache 数组的过程。上一篇已经分析过了,这里就不再重复了。 从上述计算 high 的过程中可以看出, java.lang.Integer.IntegerCache.high参数的设置必须要大于127的整数 ,否则该设置就是无效的。
由于缓存机制的变化, Integer.valueOf 的实现也发生一些变化,如下所示。 实际上,也就是只对 IntegerCache.low 和 IntegerCache.high 之间的值返回缓存。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
复制代码
java.lang.Integer.IntegerCache.high java -Djava.lang.Integer.IntegerCache.high=xxx Main.class -Djava.lang.Integer.IntegerCache.high=xxx java.lang.Integer.IntegerCache.high
最后,这里为什么 low 是一个固定值-128? 按理,我们也是需要扩充负数的缓存范围的。至今也没有一个开发人员给出合理的解析。