前言
最近跟许多朋友聊了下,在这个“跳槽”的黄金季节,大家都有点蠢蠢欲动,所以最近就多聊聊面试的时候需要注意的一些问题,这些问题不一定多深奥,多复杂,但是一不注意的话却容易掉坑。下面看一下面试的时候经常遇到的一段代码:
public class IntegerDemo {
public static void main(String[] args) {
Integer numA = 127;
Integer numB = 127;
Integer numC = 128;
Integer numD = 128;
System.out.println(“numA == numB : “+ (numA == numB));
System.out.println(“numC == numD : “+ (numC == numD));
}
}
根据大家以往的经验,会认为上面的代码用“==“符号来比较,对比的是对象的引用,那么 ABCD 是不同的对象,所以输出当然是 false 了。我在《“==”、“equals()”、“hashcode()”之间的秘密》这篇文章也讨论过。那么事实也是如此吗?下面看一下输出结果:
numA == numB : true
numC == numD : false
What?这个输出结果怎么跟以往的认知有所出入呢?在我们的代码“Integer numA = 127”中,编译器会把基本数据的“自动装箱”(autoboxing) 成包装类, 所以这行代码就等价于“Integer numA = Integer.valueOf(127)”了, 这样我们就可以进入 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);
}
//Integer 静态内部类
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() {}
}
从上面的源码可以看到,valueOf 方法会先判断传进来的参数是否在 IntegerCache 的 low 与 high 之间,如果是的话就返回 cache 数组里面的缓存值, 不是的话就 new Integer(i) 返回。
那我们再往上看一下 IntegerCache,它是 Integer 的内部静态类,low 默认是 -128,high 的值默认 127,但是 high 可以通过 JVM 启动参数 XX:AutoBoxCacheMax=size 来修改(如图),如果我们按照这样修改了,然后再次执行上面代码,这时候 2 次输出都是 true,因为缓存的区间变成 -128~200 了。
但是如果我们是通过构造器来生成一个 Integer 对象的话,下面的输出都是 false。因为这样不会走 ValueOf 方法,所以按照正常的对象对比逻辑即可。
public class IntegerDemo {
public static void main(String[] args) {
Integer numA = new Integer(127);
Integer numB = new Integer(127);
Integer numC = new Integer(128);
Integer numD = new Integer(128);
System.out.println(“numA == numB : “+ (numA == numB));//false
System.out.println(“numC == numD : “+ (numC == numD));//false
}
}
还有需要注意的一点是,此类缓存行为不仅存在于 Integer 对象。还存在于其他的整数类型 Byte,Short,Long,Character。但是能改变缓存范围的就只有 Integer 了。
结语
有时候往往越简单的知识越容易掉坑里,所以要保持自己的求知欲,不断巩固的基础,才能让自己在面试的时候不会栽跟头。
文章始发于微信公众号《深夜里的程序猿》,每天分享最干的干货,转载请注明出处,侵权必究。