对象包装器与自动装箱
有时, 需要将 int 这样的基本类型转换为对象。 所有的基本类型都有一个与之对应的类。
例如,integer 类对应基本类型 int。通常, 这些类称为包装器 ( wrapper ) ,这些对象包装器类拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character 、Void 和 Boolean (前 6 个类派生于公共的超类 Number)。
对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。
同时, 对象包装器类还是 final , 因此不能定义它们的子类
假设想定义一个整型数组列表。而尖括号中的类型参数不允许是基本类型,也就是说,不允许写成 ArrayList。这里就用到了 Integer 对象包装器类。我们可以声明一个 Integer对象的数组列表。
ArrayList<Integer> list = new ArrayList<>();
由于每个值分别包装在对象中, 所以 ArrayList 的效率远远低于 int[ ] 数组,幸运的是,有一个很有用的特性, 从而更加便于添加 int 类型的元素到ArrayList中。下面这个调用
list.add(3);
将自动地变换成
list.add (Integer.value0f(3));
这种变换被称为自动装箱(autoboxing)。
相反地, 当将一个 Integer 对象赋给一个 int 值时, 将会自动地拆箱。
int n = list.get(i);
自动翻译成
int n = list.get(i).intValue();
甚至在算术表达式中也能够自动地装箱和拆箱。例如,可以将自增操作符应用于一个包装器引用
Integer n = 3;
n++;
大多数情况下,容易有一种假象, 即基本类型与它们的对象包装器是一样的,只是它们的相等性不同。大家知道, == 运算符也可以应用于对象包装器对象, 只不过检测的是对象是否指向同一个存储区域。因此,下面的比较通常不会成立:
Integer a = 1000;
Integer b = 1000;
if (a = b)
自动装箱规范要求 boolean、byte、char 127, 介于 -128 ~ 127 之间的 short 和int 被包装到固定的对象中。例如,如果在前面的例子中将 a 和 b 初始化为 100,对它们进行比较的结果一定成立。
关于自动装箱还有几点需要说明。
首先, 由于包装器类引用可以为 null, 所以自动装箱有可能会抛出一个 NullPointerException 异常:
Integer n = null;
System.out.println(2 * n); // Throws NullPointerException
如果在一个条件表达式中混合使用 Integer 和 Double 类型, Integer 值就会拆箱,提升为 double, 再装箱为 Double
Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x); // Prints 1.0
装箱和拆箱是编译器认可的,而不是虚拟机。编译器在生成类的字节码时, 插人必要的方法调用。虚拟机只是执行这些字节码。
使用数值对象包装器还有另外一个好处,可以将某些基本方法放置在包装器中