Java基础——对象包装器与自动装箱

包装器

如果我们想在数组列表中存入一些整型数据,像这样子存肯定是不可以的:

var list = new ArrayList<int>();//错误!尖括号里不允许是基本类型

其实所有的基本类型都有一个与之对应的类。
int -> Integer
long -> Long
short -> Short
byte -> Byte
float - > Float
double -> Double
char -> Character
boolean -> Boolean
这些类被称为包装器
关于包装器有两点需要注意:
1.包装器类是不可变的。
也就是说一旦构造了包装器就不允许更改包装在其中的值了。对于这句话有的小伙伴可能会有困惑,比如下边这段代码

 Integer a = 10;
 a = 11;
 System.out.println(a);

输出结果是11啊,这值不是更改了吗。但事实其实是,类似于指针,a最初指向内存中的地址A,里边有个数10,然后a又指向了新开辟出的地址B,里面存个11,而A地址中的10并没有发生改变,而是你的引用变了。
2.包装器类是final,不允许派生子类。

自动装箱和拆箱

我们先建立个整型数组列表:

var list = new ArrayList<Integer>();

我们可以很容易的向这个数组列表中加入一个新的数据:

list.add(1);

这段代码会自动变换成:

list.add(Integer.valueOf(1));

这种变换就是自动装箱。不过呢这些都是编译器要做的,它会在生成字节码文件的时候插入必要的方法调用,虚拟机只是去执行。
相反,我们还可以将一个Integer对象赋给一个int值:

int n = list.get(i);

它将转换成:

int n = list.get(i).intValue();

甚至这些操作对于算术表达式也是适用的,比如自增,自减:

Integer a = 1;
a++;

关于这个自动装箱和拆箱也有几点需要说明:
1.比较两个包装器对象调用equals方法。
在比较两个整型数时候我们习惯用 ==运算符,同样它也可以用在包装器对象上,不过就可能会失败,因为这个运算符检测的是对象是否具有相同的内存位置。像这个例子:

Integer a = 1000;
Integer b = 1000;
System.out.println(a==b)

输出的结果就是false。不过呢自动装箱规范要求boolean,byte,char<=127,介于-128和127之间的short和int被包装在对象中。所以如果把上边的例子改一下,像这样:

Integer a = 100;
Integer b = 100;
System.out.println(a==b)

那么输出的结果就是true。很显然我们不希望有这种一会儿正确一会儿错误的结果,所以一个好的办法就是调用equals方法。
2.包装器类引用null,自动装箱可能抛异常。

Integer n = null;
System.out.println(2*n);//throws NullPointerException

3.一个条件表达式如果混用了Integer和Double,Integer会拆箱,提升为Double,再装箱。

Integer n = 1;
Double x = 2.0;
System.out.println(true?n:x)//prints 1.0

4.数字字符串转换为数值
利用Integer.parseInt();方法可以很方便的把一个字符串形式的数转换成数值

String str = "123";
int a = (int)str//天啦噜!这肯定不可以的啦!
int a = Integer.parseInt(str);//可以呦

PS:更多有趣的小方法可以去查查API
加个鸡腿吧!
Java基础——对象包装器与自动装箱_第1张图片
参考资料:
[1]凯·S.霍斯特曼著;林琪等译.Java核心技术 卷I.[M].第十一版.北京:机械工业出版社,2019.192-195.

你可能感兴趣的:(Java基础)