装箱转换是一个隐式操作,它将基本类型(例如int)自动地放置到它对应的引用类型(在本例中是Integer)的一个实例中。拆箱则是相反的操作,即将一个引用类型(例如Integer)转换为它的基本类型(int)。如果没有装箱,就需要按如下方式将int基本类型添加到一个集合(它容纳Object类型)中:
Integer intObject;
int intPrimitive;
ArrayList arrayList = new ArrayList();
intPrimitive = 11;
intObject = new Integer(intPrimitive);
arrayList.put (intObject); // cannot add intPrimitive directly
尽管此代码很简单,但是完全没必要这么冗长。随着装箱转换的引入,以上代码可以重新编写如下:
int intPrimitive;
ArrayList arrayList = new ArrayList();
intPrimitive = 11;
// here intPrimitive is automatically wrapped in an Integer
arrayList.put(intPrimitive);
这样,将不再需要创建一个Integer对象来将一个int放置到集合中。在结果引用类型的value()方法(例如Integer的intValue())等于源基本类型的值时,装箱转换将会发生。可以参考下面的表1-1来查看所有有效的装箱转换。如果存在任意其他的类型,那么装箱转换将是一种恒等转换(将类型转换为其自身类型)。注意,由于引入了装箱转换,一些引用基本类型的被禁转换也不再被禁止,因为基本类型现在也可以被转换成某些引用类型。
因为装箱和拆箱操作是一种转换操作,所以它们无需程序员的特定指令即可自动发生(与类型转换(casting)不一样,类型转换是一种显式操作)。存在几种可以出现装箱/拆箱转换的上下文环境。
(1)赋值
当表达式的值被赋予一个变量时,会发生赋值转换。当表达式的类型与变量的类型不匹配,并且不会存在数据丢失的危险时,转换将会自动发生。发生转换的优先级首先是恒等转换,接着是扩展基本类型转换,然后是扩展引用类型转换,最后才是新的装箱(或者拆箱)转换。如果这些转换都无效,那么编译器将会发出一个错误。
(2)方法调用
进行方法调用时,如果参数类型没有精确匹配那些传入的参数,那么就可能发生一些转换。这些转换被认为是方法调用转换。每个在类型上没有精确匹配方法签名中对应参数的参数都将会被转换。可能发生的转换依次是恒等转换、扩展基本类型转换、扩展引用类型转换,然后是新的装箱(或者拆箱)转换。
在多个方法都匹配特定方法调用时,要选择最精确的方法。匹配最精确方法的规则外加装箱转换只需稍作修改。如果所有用于解决方法歧义的标准检查都失败了,那么装箱/拆箱转换将不会用于解决歧义。这样,在执行装箱转换检查时,方法调用将会被认为有歧义并且失败。
将装箱和泛型联合使用,可以编写如下代码:
import java.util.*;
public class BoxingGenericsExample {
public static void main(String args[])
{
HashMap<String, Integer> hm = new HashMap<String,Integer>();
hm.put("speed", 20);
}
}
基本类型整数20自动转换成为一个Integer类型,然后按照指定关键字被放入到HashMap中。