拆箱装箱
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 t = 1;
t. 后面没有方法Integer t =1;
t. 后面就有很多方法可调用什么是自动装箱拆箱
- 自动装箱: 自动将基本数据类型转换为包装器类型
- 自动拆箱: 自动将包装器类型转换为基本数据类型
一般我们要创建一个类的对象实例的时候,我们会这样:
Class a = new Class(parameter);
在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:
Integer i = new Integer(10);
有了自动装箱拆箱
从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:
Integer i = 10;
注意:不是
int i = 100;
实际上,执行上面那句代码的时候,系统为我们执行了:
Integer i = Integer.valueOf(10);
此即基本数据类型的自动装箱功能。
拆箱 那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:
Integer i = 10;
//装箱
int n = i;
//拆箱
底层怎么实现 Integer在装箱的时候自动调用的是Integer的
valueOf(int)
方法。而在拆箱的时候自动调用的是Integer的intValue
方法。因此可以用一句话总结装箱和拆箱的实现过程:
- 装箱过程是通过调用包装器的
valueOf()
实现的 - 拆箱过程是通过调用包装器的
xxxValue()
实现的。(xxx代表对应的基本数据类型)。
类型 | == | equals |
---|---|---|
字符串变量 | 对象在内存中的首地址 | 字符串内容 |
非字符串变量 | 对象在内存中的首地址 | 对象在内存中的首地址 |
基本类型 | 值 | 不可用 |
包装类 | 地址 | 内容 |
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
//true
System.out.println(i3==i4);
//false
}
}
结果:
true
false
输出结果表明 i1 和 i2 指向的是同一个对象,而 i3 和 i4 指向的是不同的对象。
看源码,下面这段代码是Integer的
valueOf方法
的具体实现:public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
【拆箱装箱】可以看出,在通过valueOf方法创建Integer对象的时候
- 如果数值在
[-128,127]
之间,便返回指向IntegerCache.cache
中已经存在的对象的引用 - 否则创建一个新的Integer对象
==与equals()
- 当
==
运算符的- 两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象
- 如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发
自动拆箱
的过程)
- 对于包装器类型,
equals()
并不会进行类型转换
public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
//true
System.out.println(e==f);
//false
System.out.println(c==(a+b));
//true
System.out.println(c.equals(a+b));
//true
System.out.println(g==(a+b));
//true
System.out.println(g.equals(a+b));
//false
System.out.println(g.equals(a+h));
//true
}
}
true
false
true
true
true
false
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了
算数运算触发自动拆箱
注意不同类型触发类型转换
参考文章
JAVA基本类型和包装类
深入剖析Java中的装箱和拆箱
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- Java|Java基础——数组
- RxJava|RxJava 在Android项目中的使用(一)
- java之static、static|java之static、static final、final的区别与应用
- Java基础-高级特性-枚举实现状态机