面试题
碰到一个面试题。对于这个面试题,大部分人的回答,要不全是false,要不全是true,但事后运行下,结果却是true false, 为什么会出现不一致的现象?
public class Test03
{
public static void main(String[] args) throws Exception {
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
// 对于引用类型的变量之间的比较是引用,而非变量的值
System.out.println(f1 == f2);
System.out.println(f3 == f4);
}
}
原理解析
首先,需要了解 java 中的自动装箱、拆箱机制。拿上面的赋值语句Integer f1 = 100来举例,当100这个int值赋给Integer这个对象时,就会出现装箱现象,也就是把基本类型包装成引用类型,系统为我们执行了:Integer i = Integer.valueOf(100); 查阅下Integer源码,就会发现如果在某个范围内,会直接从这个IntegerCache中获取。那我们再来看下这个IntegerCache源码,原来IntegerCache是Integer的内部类,同时也发现,就是Integer内部实现了一个缓存机制。缓存的范围为-128 到 127(这个值可以进行设置),当被赋的值在这个范围内的时候,就直接从缓存池中取。
现在回到面试题中,f1 和 f2 被赋的值均为100,在这个范围内,所以这两个变量其实引用的是同一个值。与此同时,使用引用类型的变量使用== 进行比较时,其实比较的两个对象的引用,故而f1 == f2 结果为 true。而 f3 和 f4 被赋的值超出了范围,需要new 一个 Integer对象出来,引用肯定是不同的,所以结果为false。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
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() {}
}
java中其他缓存的对象
这种缓存行为不仅适用于Integer对象。针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象
有 ShortCache 用于缓存 Short 对象
有 LongCache 用于缓存 Long 对象
有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。