为什么我们在Java中使用自动装箱和取消装箱?

2022-08-31 11:00:01

自动装箱是 Java 编译器在基元类型及其相应的对象包装类之间进行的自动转换。例如,将整数转换为整数,将双精度转换为双精度,依此类推。如果转换以另一种方式进行,则称为取消装箱。

那么为什么我们需要它,为什么我们在Java中使用自动装箱和拆箱呢?


答案 1

需要一些上下文来充分理解其背后的主要原因。

基元与类

Java 中的原始变量包含值(整数、双精度浮点二进制数等)。由于这些值可能具有不同的长度,因此包含它们的变量也可能具有不同的长度(考虑 vs)。floatdouble

另一方面,类变量包含对实例的引用。在许多语言中,引用通常实现为指针(或与指针非常相似的东西)。这些东西通常具有相同的大小,无论它们引用的实例的大小如何(,,,等)。ObjectStringInteger

类变量的这一属性使它们包含的引用在一定程度上可互换。这允许我们做我们称之为替换的事情:从广义上讲,使用特定类型的实例作为另一个相关类型的实例(例如,使用a作为)。StringObject

基元变量不能以相同的方式互换,无论是彼此之间还是与 .最明显的原因(但不是唯一的原因)是它们的大小差异。这使得基元类型在这方面不方便,但我们在语言中仍然需要它们(原因主要归结为性能)。Object

泛型和类型擦除

泛型类型是具有一个或多个类型参数的类型(确切的数字称为泛型 arity)。例如,泛型类型定义具有类型参数 ,该参数可以是 (生成具体类型 )、()、() 等。List<T>TObjectList<Object>StringList<String>IntegerList<Integer>

泛型类型比非泛型类型复杂得多。当它们被引入Java时(在其初始发布之后),为了避免对JVM进行彻底的更改并可能破坏与旧二进制文件的兼容性,Java的创建者决定以侵入性最小的方式实现泛型类型:实际上,所有具体类型都被编译为(二进制等效物)(对于其他类型, 绑定可能不是 ,但你明白了)。在此过程中,泛型 arity 和类型参数信息会丢失,这就是我们称之为类型擦除的原因。List<T>List<Object>Object

将两者放在一起

现在的问题是上述现实的组合:如果在所有情况下都变为,那么T必须始终是可以直接分配给Object的类型。其他任何事情都不能被允许。因为,正如我们之前所说,并且 不能与 互换,所以不能有 一个 ,或者(除非 JVM 中存在一个明显更复杂的泛型实现)。List<T>List<Object>intfloatdoubleObjectList<int>List<float>List<double>

但是 Java 提供了类似 的类型,这些类型将这些基元包装在类实例中,使它们有效地可替换为 ,从而允许泛型类型间接地与基元一起工作(因为您可以拥有 、等)。IntegerFloatDoubleObjectList<Integer>List<Float>List<Double>

创建 a from a、 a from a 等的过程称为装箱。反之称为取消装箱。因为每次要使用它们时都必须对基元进行装箱,这很不方便,所以在某些情况下,语言会自动执行此操作 - 这称为自动装箱IntegerintFloatfloatObject


答案 2

自动装箱用于将基元数据类型转换为其包装类对象。包装类提供了要在基元类型上执行的各种功能。最常见的例子是:

int a = 56;
Integer i = a; // Auto Boxing

之所以需要它,是因为程序员很容易能够直接编写代码,而JVM将负责装箱和拆箱。

当我们使用java.util.Collection类型时,自动装箱也派上了用场。当我们要创建基元类型的集合时,我们不能直接创建基元类型的集合,我们可以只创建对象的集合。例如:

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

包装类

Java的8个基元类型(byte,short,int,float,char,double,boolean,long)中的每一个都与它们相关联。这些 Wrapper 类具有预定义的方法,用于对基元数据类型预形成有用的操作。

包装类的使用

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

包装类提供了许多有用的函数。在这里查看java文档

取消装箱与自动装箱相反,在自动装箱中,我们将包装类对象转换回其基元类型。这是由JVM自动完成的,因此我们可以使用包装类进行某些操作,然后将它们转换回基元类型,因为基元导致更快的处理速度。例如:

Integer s = 45;
int a = s; auto UnBoxing;

对于处理对象的集合,仅使用自动取消装箱。操作方法如下:

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 

推荐