最近面试遇到了一道基础题。题目如下
Integer a = new Integer(120);
Integer b = new Integer(120);
System.out.println(a == b);
Integer c = 120;
Integer d = 120;
System.out.println(c == d);
Integer e = 130;
Integer f = 130;
System.out.println(e == f);
正确的输出结果应该是
false true false
首先,我们都知道 ==,基本数据类型比较的是值,引用数据类型比较的是地址值。而包装类属于引用数据类型,所以比较的是地址值。所以a==b
结果为false,因为a和b都是new()
出来的,是两个对象,值相同,地址值不同。
我们知道Integer c = 120;
会自动装箱,java通过Integer.valueOf(120)
来实现。既然如此,为什么c==d
为true而e==f
为false?具体的原因就需要看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
在low
和high
之间,则从IntegerCache.cache[]
中返回一个对象。否则是new一个对象。结合c==d
为true,e==f
为false,我们就能定位问题的关键了,在与IntegerCache
中的实现逻辑。
IntegerCache源码如下:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
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);
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() {}
}
从源码中我们看到,low
为-128,high
默认为127。在IntegerCache中有一个静态代码块,在该类初始化时,会创建一个Integer cache[]
。这里会缓存 -128~127
共计256个对象。
经过源码分析,我们已经能够明白为什么c==d
为true,e==f
为false了。120在-128~127
之间,所以直接从Integer.IntegerCache#cache[]
中获取,地址值相同。而130在-128~127
之外,所以是new出的新对象,地址值也就不同。同样,这也就是为什么包装类建议使用equals()
方法比较。
通过查看其它包装类的源码,我们能够发现只有部分包装类才有cache。如下表:
类 | 是否有Cache | 最小值 | 最大值 |
---|---|---|---|
Boolean | 无 | – | – |
Byte | ByteCache | -128 | 127(固定) |
Short | ShortCache | -128 | 127(固定) |
Charachter | CharachterCache | 0 | 127(固定) |
Integer | IntegerCache | -128 | 127(默认,java.lang.Integer.IntegerCache.high) |
Long | LongCache | -128 | 127(固定) |
Float | 无 | – | – |
Double | 无 | – | – |