1. 自动装箱与自动拆箱
那我们来分析Integer i = 5;
的过程;
在jdk1.5以前,这样的代码是错误的,必须要通过Integer i = new Integer(5);
这样的语句实现;
而在jdk1.5以后,Java提供了自动装箱的功能,只需Integer i = 5;
这样的语句就能实现基本数据类型传给其包装类,JVM为我们执行了Integer i = Integer.valueOf(5);
。
相对应的,把基本数据从对应包装类中取出的过程就是拆箱,如
源码方面,装箱过程是通过调用包装器的valueOf
方法实现的,而拆箱过程是通过调用包装器的xxxValue
方法实现的。(xxx代表对应的基本数据类型)
2. 比较大小
2.1 整型
|
|
对于Integer,需要注意它的valueOf
方法:
这里引入了IntegerCache
,缓存-128到127之间的常用数值,注意,范围外的数值也有可能被缓存。
即在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
上面代码中,n1和n2的数值都为1,在缓存范围内,所以引用了同一个对象。
类似的,Byte、Character、Short、Integer、Long这几个整型包装类都会缓存[-128,127]之间的数值。
2.2 浮点型
与整型不同,浮点型包装类Float和Double的valueOf并不会缓存常用值,而是直接新建对象:
2.3 布尔型
|
|
接下来看布尔类型包装类Boolean的valueOf方法:
可以看出来,布尔类型的自动装箱会返回两个静态常量值中的一个。
2.4 类型转换
|
|
a + b 运算符操作,先进行拆箱,计算得到int型的3,然后在进行封箱操作,传入equals方法。
这里面需要注意的是:
- 当 “==” 运算符的两个操作数都是包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。
- 对于包装器类型,equals方法并不会进行类型转换。
重点看(3)(4)(5)。
(1)和(3)由于 a+b 包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。
(2)(4)(5)对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法。不同类型进行equals方法比较肯定不相等。
3. 空指针
|
|
在执行a > 0
时,需要对a进行拆箱操作,也就是调用a的intValue方法,而a为空,则抛出NPE。
因此,对于包装类,需要先进行判空检验。