Java为每种基本数据类型都提供了对应的包装器类型。
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class):
基本数据类型 | 包装器类型 |
---|---|
int(4字节) | Integer |
byte(1字节) | Byte |
short(2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char(2字节) | Character |
boolean(未定) | Boolean |
为什么自动装箱拆箱
基本数据类型不是对象,也就是使用int、double、boolean等定义的变量、常量。
基本数据类型没有可调用的方法。
int t = 1;
t. 后面没有方法
Integer t =1;
t. 后面就有很多方法可调用
什么是自动装箱拆箱
- 自动装箱: 自动将基本数据类型转换为包装器类型
- 自动拆箱: 自动将包装器类型转换为基本数据类型
装箱
Java SE5之前
一般我们要创建一个类的对象实例的时候,我们会这样:
1 | Class a = new Class(parameter); |
在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:
1 | Integer i = new Integer(10); |
有了自动装箱拆箱
从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:
1 | Integer i = 10; |
注意:不是 int i = 100;
实际上,执行上面那句代码的时候,系统为我们执行了:
1 | Integer i = Integer.valueOf(10); |
此即基本数据类型的自动装箱功能。
拆箱
那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:
1 | Integer i = 10; //装箱 |
底层怎么实现
Integer在装箱的时候自动调用的是Integer的valueOf(int)
方法。而在拆箱的时候自动调用的是Integer的intValue
方法。
因此可以用一句话总结装箱和拆箱的实现过程:
- 装箱过程是通过调用包装器的
valueOf()
实现的 - 拆箱过程是通过调用包装器的
xxxValue()
实现的。(xxx代表对应的基本数据类型)。
一些运用
Integer.valueOf(int i)
“==”和“equal”的区别:
类型 | == | equals |
---|---|---|
字符串变量 | 对象在内存中的首地址 | 字符串内容 |
非字符串变量 | 对象在内存中的首地址 | 对象在内存中的首地址 |
基本类型 | 值 | 不可用 |
包装类 | 地址 | 内容 |
1 | public class Main { |
结果:
1 | true |
输出结果表明 i1 和 i2 指向的是同一个对象,而 i3 和 i4 指向的是不同的对象。
看源码,下面这段代码是Integer的valueOf方法
的具体实现:
1 | public static Integer valueOf(int i) { |
可以看出,在通过valueOf方法创建Integer对象的时候
- 如果数值在
[-128,127]
之间,便返回指向IntegerCache.cache
中已经存在的对象的引用 - 否则创建一个新的Integer对象
上面的代码中 i1 和 i2 的数值为100,因此会直接从cache中取已经存在的对象,所以 i1 和 i2 指向的是同一个对象,而 i3 和 i4 则是分别指向不同的对象。
==与equals()
- 当
==
运算符的- 两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象
- 如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发
自动拆箱
的过程)
- 对于包装器类型,
equals()
并不会进行类型转换
1 | public class Main { |
1 | true |
c==d
和e==f
分析见上一节第三句由于 a+b 包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。
c.equals(a+b)
a+b
触发拆箱,会先各自调用intValue
方法- 得到了加法运算后的数值之后
- 触发装箱过程,调用
Integer.valueOf
方法 - 进行equals()比较
g.equals(a+b)
a+b
触发拆箱,会先各自调用intValue
方法- 得到了加法运算后的数值,但类型还是int
- 触发装箱过程
- 进行equals()比较,Integer与Long 类型不同,false
g.equals(a+h)
- 先自动触发拆箱,就变成了int类型和long类型相加
- 这个会触发类型晋升,结果是long类型的
- 然后会触发装箱过程,就变成Long了
总结:
算数运算触发自动拆箱
注意不同类型触发类型转换