Integer 比较问题

缘起

一道面试题

1
2
3
4
5
6
7
8
9
10
11
//-128--127之间
Integer i1 = 100;
Integer i2 = 100;

System.out.println(i1 == i2);

//大于127
Integer i3 = 200;
Integer i4 = 200;

System.out.println(i3 == i4);

答案是什么呢?

分析

答案是 true false. 为什么呢? 因为我们知道int赋给Integer其实是装箱,Integer赋给int其实是拆箱——拆箱、装箱的概念since JDK5.

而上述程序中显然是装箱. 装箱会调用Integer.valueOf(int) 方法

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

方法很容易看懂——对于来的请求——“嗨~ 我需要i对应的Integer实例”,先会去IntegerCache中找找看,如果有的话,就直接返回了,没找到才使用new Integer(int i)去构建新的Integer实例

1
2
3
4
5
6
7
8
9
10
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public Integer(int value) {
this.value = value;
}

该方法的注释是

1
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor 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.

翻译过来就是

1
返回代表value(入参)的Integer实例对象. 如果并不需要新的Integer实例(例如,之前已经获取过5对应的Integer实例了,现在又要来获取5对应的Integer实例,那么应该使用Integer.valueOf(5), 而不应该使用new Integer(5), 因为前者会先去IntegerCache中找找看,而new Integer(5)是找都不找就直接构造新的Integer实例了),那么相比直接使用构造器Integer(int)来构造新的Integer实例,更应该使用本方法来获取Integer实例. 本方法预先默认会缓存[-128, 127]中所有整数对应的Integer实例(缓存进IntegerCache的cache属性),其中127这个数字是可以定制的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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 i1 和 Integer i2 是同一个Integer实例——他们都来自Integer.cache中,而i3和i4 则是不同Integer实例,因为他们最终都调用了new Integer(int i)这个构造器各自产生了新的Integer实例.