要了解Integer对象之间的比较问题,我们先来看一道面试题。
public class Test {
public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
上面两段打印,在默认的参数配置下输出如下:
这道题其实有多个问题值得我们去思考。
自动装箱
首先我们要知道当你编写这段代码时,
Integer i1 = 127
编译器到底是如何进行自动装箱的,也就是基本类型int 127,是如何赋值给对象类型Integer的。
首先我们通过javap命令,可以进行反编译,查看到java编译器生成的字节码文件,关键内容如下:
通过查看字节码文件便知,原来编译器是通过调用Integer.valueOf()这个方法帮我们把int类型装换成Integer类型的。
找到这个方法,可以看到这个方法并不是直接返回Integer对象的,如果满足if中的条件那么看起来这个对象是从一个缓存中获取的。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer对象类型为什么进行==比较结果为true?
了解装箱过程后,我们找到valueOf的方法,应该就可以解释为什么==比较为true了,肯定是因为满足了if中的条件,并没有返回new Integer(i)这个对象。
为什么一个为true一个为false?
这个问题的关键就在于这个缓存了,这段代码应该很容器看出来,IntegerCache默认帮我们预先生成了从-128到127的Integer对象,并且放入了cache的数组中,当我们int值在这个范围内的时候,实际上并没有重新创建一个Integer对象,而是从缓存中直接获取,否则就新创建一个Integer对象,所以最终输出为一个true一个false。
/**
* 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() {}
}
设置缓存范围
通过上面这个源码我们可以看出,这个缓存的范围下限到-128不支持修改,上限127好像是可以通过参数配置的,源码注释上也给出了具体的说明,就是这个参数-XX:AutoBoxCacheMax。
修改为256后,再执行一次应该结果都为true了,读者可以自行实验。