前言
自动装箱和拆箱从Java 1.5开始引入,目的是让原始类型值与对应的包装对象之间可以自动的相互转换,比如将int
类型值转换成Integer
对象称为装箱,反之将Integer
对象转换成int
类型值称为拆箱。因为这里的装箱和拆箱是自动进行的而非人为转换,所以就称为自动装箱和拆箱。
在Java中,原始类型byte
、short
、char
、int
、long
、float
、double
、boolean
分别对应的包装类为Byte
、Short
、Character
、Integer
、Long
、Float
、Double
、Boolean
。
实现原理
自动装箱与拆箱其实是编译器自动为我们调用了相关方法,自动装箱是通过调用包装类的valueOf()
方法实现的,而自动拆箱是通过调用包装类的xxxValue()
方法实现的(xxx代表对应的基本数据类型)。
何时发生自动装箱和拆箱
自动装箱和拆箱主要发生在两种情况,一种是赋值时,另一种是在方法调用时。
赋值时
这是最常见的一种情况,在Java 1.5以前我们需要手动地进行转换才行,而现在所有的转换都是由编译器来完成。
1 | //before autoboxing |
方法调用时
这是另一个常用的情况,当我们在方法调用时,我们可以传入原始数据值或者对象,同样编译器会帮我们进行转换。
1 | public static Integer show(Integer iParam){ |
show
方法接受Integer
对象作为参数,当调用show(3)
时,会将int
值转换成对应的Integer
对象,这就是所谓的自动装箱,show
方法返回Integer
对象,而int result = show(3);
中result
为int
类型,所以这时候发生自动拆箱操作,将show
方法的返回的Integer
对象转换成int
值。
需要注意的问题
自动装箱与拆箱虽然为我们省下了很多不必要的工作,使代码更加简洁清晰,但是如果使用不当,则会引起性能问题。
循环中的自动装箱
自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能:
1 | Integer sum = 0; |
上面的代码sum+=i
可以看成sum = sum + i
,但是+
这个操作符不适用于Integer
对象,首先sum
进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成Integer
对象。其内部变化如下:1
2int result = sum.intValue() + i;
Integer sum = Integer.valueOf(result);
由于我们这里声明的sum
为Integer
类型,在上面的循环中会创建将近4000个无用的Integer
对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。
对象和原始类型值的比较
包装类对象和原始类型值的比较是很容易出错的一个地方,需要注意的是,==
可以用于原始值的比较,也可以用于对象的比较,但是用于对象之间的比较时,比较的不是对象代表的值,而是检查两个对象是否是同一对象。而当其中一个操作数是原始类型值或算术运算时,则比较的是数值(触发自动拆箱)。以下几个例子基本可以涵盖所有情况:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d); // 比较对象是否为同一个,因为 Integer 会缓存-128~127之间的对象
System.out.println(e==f); // 比较对象是否为同一个,数值在缓存之外
System.out.println(c==(a+b)); // a+b运算触发自动拆箱,之后数值比较
System.out.println(c.equals(a+b)); // a+b运算触发自动拆箱,之后自动装箱
System.out.println(g==(a+b)); // a+b运算触发自动拆箱,之后数值比较
System.out.println(g.equals(a+b)); // a+b运算触发自动拆箱,之后自动装箱,由于不是同一类型,equals() 返回 false
System.out.println(g.equals(a+h)); // a+h运算触发自动拆箱,int类型晋升为long,之后自动装箱为Long,equals() 返回 true
}
}
其运行结果如下:1
2
3
4
5
6
7true
false
true
true
true
false
true