自动装箱是Java编译器在原始类型及其对应的对象包装器类之间进行的自动转换。例如,将int转换为Integer,将double转换为Double,依此类推。如果转换结果相反,则称为拆箱。
那么,为什么我们需要它?为什么要在Java中使用自动装箱和拆箱呢?
需要一些上下文来充分理解其背后的主要原因。
基元与类 Java中的原始变量包含值(整数,双精度浮点二进制数等)。由于这些值的长度可能不同,因此包含它们的变量的长度也可能不同(请考虑float与double)。
float
double
另一方面,类变量包含对实例的引用。引用通常在许多语言中实现为指针(或与指针非常相似的东西)。这些东西通常具有相同的大小,而不管它们指的是(实例的大小Object,String,Integer,等)。
Object,String,Integer
类变量的此属性使它们包含的引用可以互换(一定程度上)。这使我们能够执行所谓的替换:广义上讲,是将特定类型的实例用作另一种相关类型的实例(例如,将a String用作Object)。
a String
Object
原始变量不能以相同的方式互换,彼此之间也不能互换Object。最明显的原因(但不是唯一原因)是它们的大小差异。这使得原始类型在这方面不方便,但是我们仍然需要该语言中的它们(由于主要归结为性能的原因)。
泛型和类型擦除 泛型类型是具有一个或多个类型参数的类型(确切的数字称为泛型arity)。例如,通用类型定义 List<T>具有类型参数T,可以是Object(产生具体类型 List<Object>),String(List<String>),Integer(List<Integer>)等。
List<T>
List<Object>
String(List<String>),Integer(List<Integer>)
泛型类型比非泛型类型复杂得多。当他们被介绍到Java(首次发行)之后,为了避免到JVM根本变化,并与旧的二进制可能破坏兼容性,Java的创作者决定在最小侵入性的方式来实现泛型类型:所有的具体类型List<T>实际上,已被编译为(的二进制等效项)List<Object>(对于其他类型,边界可能不是Object,但你明白了)。泛型和类型参数信息在此过程中丢失,这就是为什么我们将其称为类型擦除。
将两者放在一起 现在的问题是上述现实的结合:如果在所有情况下都List<T>变为List<Object>,则T必须始终是可以直接分配给的类型Object。不允许其他任何事情。因为,正如我们之前所说,int,float并且double不与互换Object,不能有一个List<int>,List<float>或List<double>(除非仿制药的显著更复杂的实现JVM中的存在)。
List<int>,List<float>
List<double>
但是Java提供喜欢的类型Integer,Float以及Double其在类实例包装这些原语,使他们有效地作为替代Object,从而使泛型类型与原语间接地工作,以及(因为你可以有List<Integer>,List<Float>,List<Double>等)。
Integer
Float
Double
List<Integer>,List<Float>,List<Double>
创建的过程Integer,从一个int,一个Float从float等,被称为拳击。相反的称为拆箱。因为每次使用原始语言都必须对原始语言进行装箱Object是很不方便的,所以在某些情况下该语言会自动执行此操作- 这称为autoboxing。
int
个Float
autoboxing