Java中的自动拆装箱
Java语言中,基本类型和它对应的封装类型直接可以相互复制,共同参与运算。其实,经过编译后并不是直接使用不同的类型来进行赋值和运算,而是采用了自动拆装箱的方式把数据类型进行了变化。自动拆装箱只是JDK语法糖技术中的一个。如下的代码是可以通过编译并且成功运行的:
public void assignment(){
int a = 1;
Integer b = a;
Integer c = 1;
int d = c;
int e = a + b;
Integer f = c + d;
System.out.println(e);
System.out.println(f);
}
通过javap命令,的这个方法的虚拟机指令序列
public void assignment();
Code:
0: iconst_1
1: istore_1
2: iload_1
3: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
6: astore_2
7: iconst_1
8: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_3
12: aload_3
13: invokevirtual #3 // Method java/lang/Integer.intValue:()I
16: istore 4
18: iload_1
19: aload_2
20: invokevirtual #3 // Method java/lang/Integer.intValue:()I
23: iadd
24: istore 5
26: aload_3
27: invokevirtual #3 // Method java/lang/Integer.intValue:()I
30: iload 4
32: iadd
33: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
36: astore 6
38: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
41: iload 5
43: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
46: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
49: aload 6
51: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
54: return
第13行的指令意味着,把Integer类型的值赋值给int类型变量需要利用拆箱方法Integer.intValue()先得到int类型的值,然后再赋值给int类型的变量。
第18到24行代表代码中的int e = a + b。Integer类型的变量和int类型的变量相加,Integer变量会先转换成int类型,再进行相加运算。得到的结果是int类型。
Java不通于c语言,不能重载加减乘除等运算符。所以在进行元素时,包装类型都需要拆箱成基本类型才能运算。如果包装类型为null,则会报出空指针异常。
但是,不论包装类型还是基本类型都可以通过==操作符来比较两个变量是否相等,包装类型可以使用equeals方法比较两个对象。那么,包装类型和基本类型在比较时都会进行哪些类型转换呢?看下面的实验
public void compare(){
Integer a = 129;
Integer b = 129;
int c = 129;
Integer e = 127;
Integer f = 127;
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a.equals(c));
System.out.println(e == f);
}
要想知道都在哪些地方做了类型转换,还是需要看看编译后的指令,只不过指令代码有点长不做粘贴了。最后的结论是,比较a和c时,把a拆箱成了int值。也就是==比较包装类和基本类型时,把包装类型拆箱成了基本类型。
通过上面的实验可以得出下面的结论:
1,包装类型和基础类型相互赋值时,利用对应的拆箱或装箱方法把右值转化成左值的类型。
2,包装类型和基础类型在一起混合运算(包括==),则把封装类型拆箱成基本类型
3,equals方法是包装类型特有的方法(继承自Object),基本类型不能利用这个方法比较。
这里还有一个有意思的地方,a和b是不相等的,而e和f是相等的。产生这个现象的原因是,Integer类型利用了缓存技术,在其内部缓存了从-128到127范围内的数据,每当需要这个范围内的对象的时候就会返回缓存池中的对象。那么,如果直接new两个缓存范围内的Integer对象,通过==判断它们会相等吗?不要想的那么复杂,都new了,怎么会相等。==操作符比较的是对象在内存中的位置,除非是同一个对象,不然一定不相等。