原因 :
包装类对象原本是引用对象,若使用 == 只是比较两个引用变量是否指向相同的对象。在JDK1.5之后有了自动装箱、拆箱。对于 Integer 对象来说,初始值在-128 ~ 127时会将对象放入缓存池(IntegerCache.cache),下次调用相同的值将直接复用。在该区间的Integer 对象可直接进行判读,该区间以外的对象在 Heap 上产生,不会进行复用。所以推荐使用 equals 方法进行判断。下列代码很清楚表达。
Integer a = 1;
Integer b = 1;
// 输出 ture
System.out.println(a == b);
Integer c = 123;
Integer d = 123;
// 输入 true
System.out.println(c == d);
Integer e = 129;
Integer f = 129;
// 输入 false
System.out.println(e == f);
源码 :
简单的知道原因还是不行,还是要看看Integer的源码。
// int 转 Integer 源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
发现若 i 的值在 IntegerCache.low ~ high 的范围内则返回一个缓存值。再看看 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);
// 最大数组长度 Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch(NumberFormatException nfe) {
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 缓存 [-128, 127] 区间的值
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
在 IntegerCache 源码中可以知道,只要初始化的数字在 cache[low, high]的范围内,就返回 cache 数组的数据。否则将在 Heap 上产生新的 Integer 值。JDK 中默认 IntegerCache.cache 的范围是 -128 ~ 127。 在 JVM 调优的时候通过 -XX:AutoBoxCacheMax 修改最大值。该则规约中强制使用 equals 比较所有相同类型包装类的值。因为在 JDK 中其他的包装类都有缓存机制,分别为:
- Byte 包装类有 ByteCache 用于缓存 Byte 对象,固定范围是 -128 ~ 128 、
- Short 包装类有 ShortCache 用于缓存 Short 对象,固定范围是 -128 ~ 128 、
- Long 包装类有 LongCache 用于缓存 Long 对象,固定范围是 -128 ~ 128 、
- Character 包装类有 CharacterCache 用于缓存 Character 对象,固定范围是 0 ~ 127、
- 除了 IntegerCache 其他包装类的缓存机制均不可以改变范围。