在 Java 中,基础数据类型与包装类之间的转换是我们经常使用的,但是在一些情况下会出现一些奇怪的事情。看下我们的样例
public class Test {
public static void main(String[] *args*) {
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
Integer c = 130;
Integer d = 130;
System.out.println(c == d);
}
}
按照代码本身来看,最后两个输出的肯定都是 true。
但是,现实有些时候很真实。
这是什么?两个人明明都是直接赋值的,怎么就不对了?
这个时候我们就要从底层来检查这里面的猫腻了。
首先,从 main 方法的第一句开始解释。
Integer a = 10;
这句话到底做了几件事?
- 编译器首先将基础数据类型的值通过
Integer.valueOf()
方法封装成包装类的对象。那么,在封装的时候,valueOf()
方法到底怎么做的?我们根据源码一点点的进行分析。
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
在这个方法当中,首先先判断里面的数是不是满足 IntegerCache.low 与 IntegerCache.high 当中的数,如果满足的话就直接返回该缓存数组当中的值。否则会返回一个新的 Integer 对象。
而这个 IntegerCache 又是个什么东西,我们再打开 IntegerCache 来一探究竟。
private static class IntegerCache {
// 这是 IntegerCache 初始化的最小值,注意跟虚拟机当中的属性没有任何关系。
static final int low = -128;
// 这是 IntegetCache 初始化的最大值,注意他是跟虚拟机的配置有直接的关系。
static final int high;
// 这是用来保存整数缓存池当中的元素
static final Integer[] cache;
static {
// high value may be configured by property
int h = 127;
// 获得 JVM 当中设置缓存当中最大的数值。如果没有设置,JVM 默认大小即为 127。设置方式:在 JVM 的 AutoBoxCacheMax=需要设置的缓冲区保存的最大值。
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
// 将从虚拟机当中获得的值与默认的最大值进行比较,筛选出里面的最大值
i = Math.max(i, 127);
// 取 i 与 Integer.MAX_VALUE - (-low) - 1 之间的最小值。因为这是保证缓存区的数组大小不大于 Integer.Max_Value。
h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
} catch (NumberFormatException nfe) {
// 在 parseInt 方法当中如果转换失败,会捕捉到 NumberFormatException。对这个异常默认没有任何处理。
}
}
high = h;
// 创建缓存池当中的空间,取决于最大值与最小值之间的空间。*
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// 最后通过断言,检查缓冲区的上界至少是 127。
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
自此,我们可以得到以下结论。在整数的包装类当中,在第一次创建 Integer 类的对象的时候,都会首先创建好缓存数组。当需要包装的值是在 IntegerCache 数组当中的元素的时候,就会返回数组当中的 Integer 对象。JVM 默认就会设置数组的范围为 -128 ~ 127 。除非设置 JVM 当中的 AutoBoxCacheMax 属性大小即可。