概述
1. 发现问题
先看一段代码:
Integer a = 1;
Integer b = 1;
Integer c = 500;
Integer d = 500;
System.out.print(a == b);
System.out.print(c == d);
输出是啥?输出的结果如下:
true
false
为啥?两个不都是引用吗?要输出false应该都输出false啊?下面解释原因。
2. 分析问题
2.1 字节码分析
首先我们分析自动装箱
,下面的这行代码会发生什么?
Integer a = 1;
我们用查看其编译后的字节码,看这行代码到底在干啥。
0 iconst_1 // 将int型1推送至栈顶
1 invokestatic #2 <java/lang/Integer.valueOf> // 调用Integer.valueOf方法
4 astore_1 // 将栈顶引用型数值存入第一个本地变量
显然,通过字节码我们知道上面的代码等价于如下代码:
Integer a = Integer.valueOf(1);
2.2 Integer#valueOf 方法源码分析
那么这也并不能说明文章开头的输出结果啊!那么我们再分析分析,猜测Integer.valueOf函数很可能有一些特殊的地方。
下面查看Integer.valueOf(int)
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
通过查看Integer的valueOf源码,发现,它并不是简单的new出一个Integer对象并返回,而是做了一个前置判断。通过判断代码,可以猜测这跟缓存(IntegerCache)有关,也就是IntegerCache这个类。
2.3 Integer.IntegerCache 类源码分析
那我们再看到IntegerCache这个类: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
* 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() {}
}
通过查看类的注解,我们知道Integer能够默认缓存[-128, 127]范围内的Integer对象。也就是说当我们调用Integer.valueOf(x),如果x是在[-128, 127]区间的数,那么它就能够直接返回已经创建在cache[]数组中创建过的Integer对象(这些缓存的Integer对象都存在IntegerCache类的cache[]字段中)
那么文章开头的那个输出结果也就解释得通了。
// 属于[-128, 127]区间,那么直接返回IntegerCache类cache[]已经缓存的Integer对象
Integer a = 1;
// 同上
Integer b = 1;
// 并不属于[-128, 127]区间,直接返回new Integer(500);
Integer c = 500;
// 同上,这两个返回的引用并不一样
Integer d = 500;
3. 更多
通过注释,我们也知道了:通过-XX:AutoBoxCacheMax=<size>可以调整这个缓存区间的上界。
下面我们实践一下:
public class Test {
public static void cmp(Integer i1, Integer i2){
System.out.println(i1 == i2);
}
public static void main(String[] args) {
Integer i1 = -128;
Integer i2 = -128;
cmp(i1, i2);
Integer i3 = 127;
Integer i4 = 127;
cmp(i3, i4);
Integer i5 = -129;
Integer i6 = -129;
cmp(i5, i6);
Integer i7 = 128;
Integer i8 = 128;
cmp(i7, i8);
}
}
首先我们在命令行下运行下面的代码:
>javac Test.java
>java Test
true
true
false
false
我们可以看到这正如我们预期的结果一样。那么我们再试试下面的代码:
>java -XX:AutoBoxCacheMax=129 Test
true
true
false
true
看到,最后一项输出为true,验证了参数-XX:AutoBoxCacheMax=129的正确性
4. 拓展
同样地,分析各种基本数据类型的包装类,它们的valueOf方法有下面的缓存区间
boolean
:{true, false}
byte
:缓存所有
short
:[-128, 127]
long,
:[-128, 127]
char
:['u0000', 'u007F'
]float,double
:直接new一个新的对象,并没有缓存
而这些数据类型的valueOf与Integer的又不一样,它们的缓存是固定的,而Integer的缓存是可以通过上面所描述的方法来更改的
最后
以上就是紧张凉面为你收集整理的java.lang.Integer包装类的缓存的全部内容,希望文章能够帮你解决java.lang.Integer包装类的缓存所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复