对象包装器与自动装箱

有时,需要将int这样的基本类型转换为对象。所有的基本类型都有一个与之对应的类。
例如,Integer类对应的基本类型int。
通常,这些类称为包装类

这些包装器类的名字都很明显:Integer, Long, Float, Double, Short, Byte, Character, Boolean
前六个类派生于公共的超类Number

包装器类是不可变的,也就是说,一旦构造了包装器,就不允许更改包装在其中的值。
同时,包装器类还是final,因此不能派生它们的子类。

如果想要定义一个整型数组列表,尖括号中的参数类型不允许是基本类型,也就是说,不能写成ArrayList<int>
这时候就需要用到包装器类Integer。var list = new ArrayList<Integer>

  • 由于每个值分别包装在对象中,所以ArrayList的效率远低于int[]数组。
    所以,只有在程序员操作的方便性比执行效率更重要的时候,才会考虑对较小的集合使用这种构造。

有一个很有用的特性,可以很容易地向ArrayList添加int类型的元素。
下面这个调用list.add(3)会自动变换为list.add(Integer.valueOf(3));
这种变换称为自动装箱

相反地,如果把一个Integer对象赋给一个int值时,将会自动地拆箱。
也就是说,编译器会把以下语句int n = list.get(i);转换成int n = list.get(i).intValue();

自动装箱和拆箱也适用于算术表达式。例如,可以将自增运算符应用于一个包装器引用

Integer n = 3;
n++;

编译器会自动地插入一条对象拆箱的指令,然后进行自增计算,最后再将结果装箱。

由于包装器类引用可以为null,所以自动装箱可能会抛出一个空指针异常。

如果在一个表达式中,混合使用Integer和Double类型,Integer值就会拆箱,提升为double,然后再装箱为Double。

  • 装箱和拆箱是编译器的工作,而不是虚拟机。
    编译器在生成类的字节码时会插入必要的方法调用。虚拟机只是执行这些字节码。

使用数值包装器还有一个原因,就是可以将某些基本方法放在包装器中,这样会很方便。
例如,将一个数字字符串转换成数值。

int x = Integer.parseInt(s);
// 这里与Integer对象没有任何关系,parseInt是一个静态方法。但Integer类是放置这个方法的一个好地方。
posted @ 2021-02-06 22:29  张三丰学Java  阅读(43)  评论(0编辑  收藏  举报