什么是装箱和拆箱
装箱:把基本数据类型转换成包装类。
拆箱:把包装类转换成基本数据类型。
在JDK1.5中,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能。
自动装箱与自动拆箱的实现原理
如下所示源代码
生成class文件后,再反编译得到的源代码如下所示
装箱操作是通过以下代码实现Integer a = Integer.valueOf(1);
拆箱操作是通过如下代码实现int c = a.intValue();
是编译器自动加上的代码。
图二
哪些场景会自动拆装箱
赋值操作也会进行拆箱和装箱操作除了这个还有以下几种场景
一、将基本类型放到集合里时,会自动装箱,参考图二
List<Integer> list=new ArrayList<>();
list.add(1);//1 这个值被自动装箱,并把装箱好的对象引用塞给list
int b=list.get(0);//list里的第0个对象被取出,自动拆箱,把值赋给b
二、当一个基础数据类型与包装类进行==、>、<、+、-、*、/运算时,先将包装类进行拆箱成基本数据类型。
反编译后的代码为
三、当两个包装类型进行算术运算时,也会被自动拆箱成基本类型进行
反编译后的代码如下所示
四、三目运算符,i自动拆箱,如果i为null则会抛出空指针异常
Integer i=null;
int j=1;
int k=true?i:j;//i自动拆箱
五、函数参与与返回值
源码
反编译后的代码
六、调用equals进行比较(装箱)
从执行结果可分析得知equals方法的形参最后装箱成了包装类型,虽然num3和num1与num2相加的结果数值相同,但是equals方法只有类型相同,并且数据相同的时候才会返回true,其他情况均为false。Long的equals方法如下所示
反编译得到的源码为
自动拆装箱与缓存
自动装箱时,会调用以下方法,当i的值为-128-127中的一个数时,此时会从缓存里拿对象返回,如果超出范围会new Integer
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
例如如下图所示
a==b是因为a与b是引用的同一个对象(地址相同),即缓存对象
a!=c是因为a是缓存对象,c是new的一个新对象,引用地址不同
d!=f是因为首先d超出了-128-127的范围,所以需要new一个,同事f也是一样
d!=g是因为d与g都是通过new来获取到的对象
下面我们进行一个归类:
Integer派别:Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。
Double派别:Double、Float的valueOf方法的实现是类似的。每次都返回不同的对象。没有缓存。
总结
1、装箱操作会创建对象(缓存的除外),频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。
参考