自动装箱(autoboxing)是指 Java 编译器自动将基本数据类型值转换成对应的包装类的对象,例如将 int 转换为 Integer 对象,将 boolean 转换问 Boolean 对象。而拆箱(unboxing)则是反过来转换。
基本数据类型及其包装类的对应
以下这些基本数据类型都有对应的包装类
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
double | Double |
自动装箱与拆箱的例子
自动装箱和拆箱便于我们在要求传入对象的地方直接传入基本数据类型,或者反过来。如:
自动装箱的例子
12List<Integer> list = new ArrayList<>();list.add(1);因为
list
是一个Integer
对象的集合,理论上add
方法传进去的都应该是Integer
对象,但是这里可以传递一个int
(数值2),就是因为编译器把int
转换为Integer
了。实际上编译器会把上面的代码转变为:12List<Integer> list = new ArrayList<>();list.add(Integer.valueOf(1));拆箱的例子
1234public int getFirstNumber(List<Integer> list) {int firstNumber = list.get(0);return firstNumber;}与自动装箱相反的,在这段代码中,编译器自动把
Integer
对象转换为int
基本数据类型。
如果没有自动装箱和拆箱,上面的代码将编译不通过。上面的代码得这样写才行:
|
|
可见 Java 编译器帮我们做的事情还是带来一些便利的。
什么时候会自动装箱和拆箱
自动装箱和拆箱会在以下这些情况发生:
- 把基本数据类型赋值给一个声明为其包装类类型的变量时,像
Integer obj = 1
将发生装箱;反之拆箱。 - 把基本数据类型作为函数调用的参数,而该参数的类型是其包装类时,像前面的
list.add(1);
将发生装箱;反之拆箱。 - 对包装类进行加减乘除等基本运算时,将发生拆箱。像
Integer a = 0; a += 1;
在执行+=
运算的+
运算时将发生拆箱。
可能带来的问题
虽然自动装箱与拆箱偷偷帮我们做了很多事,但是在一些情况下它也可能导致问题。
对象比较的结果
考虑以下代码:1234567public class TestJava {public static void main(String[] args) {Integer number1 = 128;Integer number2 = 128;System.out.println("number1 == number2: " + (number1 == number2));}}输出结果是:number1 == number2: false
注意这里是用==
比较两个 Integer 对象的内存指针,不是比较他们代表的值。number1
和number2
是两个不同的对象,比较结果自然是 false。继续看以下代码:
1234567public class TestJava {public static void main(String[] args) {Integer number3 = 127;Integer number4 = 127;System.out.println("number3 == number4: " + (number3 == number4));}}输出结果是:number3 == number4: true
(一脸惊恐.jpg) 几乎一样的代码,出来的结果却不一样。其实是因为 Java 虚拟机对 -128到127 的 Integer 对象做了缓存,所以number3
和number4
实际上是同一个对象,比较结果自然也就返回 true。对象的过多创建
考虑以下代码:1234Integer sum = 0;for (int i = 0; i < 1000; i++) {sum = sum + i;}上面的代码中,由于
sum
是一个Integer
对象,不能直接进行+
操作,所以会先执行sum.intValue()
拆箱,得到int
类型进行+
操作。然后再执行Integer.valueOf(sum)
进行装箱操作,得到一个Integer
对象赋值给sum
。虽然 Java 虚拟机对 -128 到 127 的Integer
对象做了缓存,但是从第 128 到 1000 次循环中总共还要创建 873 个对象。这将导致程序的性能降低甚至触发垃圾回收。而简单地把sum
的类型改为int
就可解决问题。
所以在混合使用 Java 基本数据类型及其包装类时要特别注意这些问题。