最早发现这个问题是在公众号看到的。
上代码!
public static void main(String[] args) {
Integer i=1000,x=1000;
Integer a=100,b=100;
System.out.println(i==x);
System.out.println(a==b);
}
结果是
false
true
我们知道,如果两个引用指向同一个对象,那么用==得到的结果就是true。但是两个引用指向不同的对象,即便内容是相同的,使用==也只能得到false。
所以为什么100==100 得到true呢?
我们打开Integer.java类来一探究竟。
实际上当我们执行
Integer x = 100;
的时候,它实际上内部做的是
Integer x = Integer.valueOf(100);
然后valueOf方法的内部是
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)]; //-128下标为0
return new Integer(i);
}
好像说的是,当我们初始化的值处于一个范围内的时候会直接返回
IntegerCache.cache[...]
IntegerCache是Integer的一个内部私有类,它缓存了从-128到127之间的所有整数对象。
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 a = 100,b=100;
指向了同一个对象。
为什么这里需要缓存?
合乎逻辑的解释是,jdk认为小整数的使用率比大整数要高。因此,使用相同的底层对象是有价值的,可以减少潜在的内存占用。
使用反射API会误用此功能。
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Class cache = Integer.class.getDeclaredClasses()[0];
Field myCache = cache.getDeclaredField("cache");
myCache.setAccessible(true);
Integer [] newCache = (Integer[])myCache.get(cache);
newCache[132] = newCache[133];
int a=2;
int b=a+a;
System.out.printf("%d + %d = %d",a,a,b);
}
2 + 2 = 5