基本类型和包装类型的自动装箱拆箱原理并不复杂,但是在日常使用中频率极高,如果不理解语法糖背后的奥秘,很可能陷入误区而不自知,下面以一个例子说明这个语法糖的工作原理
这个例子摘自深入理解java虚拟机第二版(强烈推荐阅读)
public static void main(String[] args) {
//part1
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
//part2
System.out.println(c == d);//1
System.out.println(e == f);//2
System.out.println(c == (a + b));//3
System.out.println(c.equals(a + b));//4
System.out.println(g == (a + b));//5
System.out.println(g.equals(a + b));//6
}
猜测结果前需要说明以下几个基本原则
- 包装类的==运算在不遇到算数运算的情况下不会自动拆箱
- 包装类型存在缓存,如Integer在-128~127是有缓存的,具体参见8大基本类型的包装类型缓存探究
- 包装类型的equals不处理转型问题
- 包装类型遇到算数运算时会进行自动拆箱
- 基本类型在需要包装类型时会进行自动装箱
结果如下
true//1
false//2
true//3
true//4
true//5
false//6
下面结合反编译出的代码分析
public static void main(String[] args) {
//part1
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(2);
Integer c = Integer.valueOf(3);
Integer d = Integer.valueOf(3);
Integer e = Integer.valueOf(321);
Integer f = Integer.valueOf(321);
Long g = Long.valueOf(3L);
//part2
System.out.println(c == d);//1
System.out.println(e == f);//2
System.out.println(c.intValue() == a.intValue() + b.intValue());//3
System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));//4
System.out.println(g.longValue() == a.intValue() + b.intValue());//5
System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));//6
}
观察原代码和反编译后代码可以看出
- part1 定义a~f时发生了自动装箱,并且使用了缓存(Integer.valueOf())
- part2 在进行==比较时发生了自动拆箱(Integer.intValue())
对于语句进行分析
- c==d 对于对象==比较的是他们的内存地址,由于c,d都是从Integer的缓存中获取的,是同一个对象,因此结果是true
- e==f 与上面相同,但是321已经不在缓存范围内,因此结果是false
- c=a+b 发生自动拆箱,进行基本类型的==比较,3=1+2,结果为true
- c.equals(a+b) 首先由规则4,a+b进行自动拆箱,然后由于规则5,equals需要包装类型,进行自动装箱且带有缓存,得到对象Integer(3),它和c都是从缓存时获取的,因此结果true
- g==a+b a+b发生自动拆箱,而后类型提升为long,因此结果为true
- g.equals(a+b) 由规则3,最终比较时为Long.equals(Integer),类型都不同,结果当然为false