Java中自动装箱与拆箱详解

时间:2021-07-05 04:41:36

自Java 5后引入了自动装箱和自动拆箱机制,自动装拆箱的出现主要是为了解决基本数据类型跟其对应的包装类之间相互转换的问题,本文将从以下几个方面详解自动装箱跟拆箱:

  • 自动装拆箱的定义及原理
  • 自动装拆箱发生的场合
  • 忽略自动装拆箱可能会带来的影响

自动装拆箱的定义及原理

Java是一门面向对象的语言,但是基本数据类型并不是对象,因此基本数据类型能够进行的操作很少,为了弥补这一不足,Java为每个基本数据类型配备了相对应的包装类,有了包装类,可以将基本数据类型当成包装类来操作,但是包装类跟基本数据之间总是免不了相互转换,在Java 5之前,两者在转换时需要我们手动添加代码,比较麻烦,随着Java的发展成熟,Java 5后出现了自动装箱跟拆箱,能够自动实现基本数据类型与其对应包装类的转换,使得我们的代码更加简单简洁。
定义:

自动装箱是将基本数据类型转换成包装类的过程(如int转换成Integer对象),自动拆箱反之,是将包装类转换成基本数据类型的过程。

原理:

自动装箱时编译器调用valueOf()方法将基本类型值转换成对象,自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成基本类型值。

自动装拆箱发生的场合

自动装拆箱发生的场合总结起来分以下2种情况:

1.赋值时

Integer iObject = 6;//自动装箱,在Java5之前必须写成Integer iObject = Integer.valueOf(6)。
int i = iObject;//自动拆箱,在Java5之前必须写成int i = iObject.intValue()。

在对Integer类型的变量直接赋值时会发生自动装箱;将Integer对象赋值给int时会发生自动拆箱。当赋值大于127时,Integer每赋值一次都会产生一个新的Integer对象。如 Integer iObject3 = 129和Integer iObject4 = 129是两个不同的对象,二者不指向同一个引用。

2.调用方法,传递对象类型参数时
比如我们不能直接在集合中放入基本类型值,因为集合只接收对象类型。我们可以将基本类型的值转换成对象,然后将这些转换的对象放入集合中。以ArrayList为例:

 ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);

整型数默认为int类型,使用Arraylist的add()方法时,int类型被自动装箱成Integer对象。

但是ArrayList的remove方法,它有remove(index)和remove(Object)两种重载,此时可能我们会有疑惑,在这里会发生自动装箱吗?答案是不会。当方法重载时,传入的该是什么类型就是什么类型,不会发生自动装拆箱。
如下代码:


public class Test {
public void autoBoxingTest(int i){
System.out.println("这是传入int类型参数的方法");
}
public void autoBoxingTest(Integer integer){
System.out.println("这是传入Integer类型的方法");
}

public static void main(String[] args) {
Test test = new Test();
int i = 3;
test.autoBoxingTest(i);//控制台输出“这是传入int类型参数的方法”,说明int并没有被自动装箱成Integer。

//手动将int装箱成Integer类型
Integer iObject = i;
test.autoBoxingTest(iObject);//控制台输出“这是传入Integer类型的方法”。
}

}

忽略自动装拆箱可能会带来的影响

自动装拆箱是编译器帮我们自动完成的事情,但是如果我们不了解自动装拆箱的原理,那么可能会给我们带来一些不必要的麻烦,比如:
1.int类型如果未初始化,它的默认值为0,但是Integer类型如果未初始化,它的初始值为null,当我们使用时可能会抛出NullPointerException的错误。如下代码:iObject未初始化,因此在自动拆箱时会找不到值。

 Integer iObject ;
if (iObject>60){
System.out.println("考试成绩合格");
}

2.自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。

Integer sum = 0;
for(int i=1000; i<5000; i++){
sum = sum+i;
}

这段程序的运行过程是:sum为Integer类型,sum=sum+i时,首先将sum自动拆箱成int类型跟i相加,然后相加完成后sum又自动装箱成Integer对象,每相加一次,就会产生一个Integer对象。 在上面的循环中会创建4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。
因此在编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。