什么是自动拆装箱
- 自动装箱: 就是将基本数据类型自动转换成对应的包装类.
- 自动拆箱:就是将包装类自动转换成对应的基本数据类型。
For example :
Integer a=1; //自动装箱
int b=a; //自动拆箱
基本数据类型与包装类对应关系,如下:
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
double | Double |
自动拆装箱是怎么实现的
我们可以通过反编译去看他是如何实现的,反编译前代码:
public static void main(String[]args){
Integer integer=1; //装箱
int i=integer; //拆箱
Double dou=2.0; //装箱
double dou2=dou; //拆箱
Float f=3f;//装箱
float f2=f;//拆箱
Byte b=4;//装箱
byte b2=b;//拆箱
Long lo=5l;//装箱
long lo2=lo;//拆箱
Character character=6;//装箱
char c2=character;//拆箱
Boolean bl=false;//装箱
boolean bl2=bl;//拆箱
Short s=8;//装箱
short s2=s;//拆箱
}
反编译后代码:
从上面反编译后的代码可以看出,自动装箱都是通过包装类的valueOf()方法来实现的.自动拆箱都是通过包装类对象的**Value()来实现的。
包装类比较数据大小是自动拆箱进行比较的吗
源码:
Integer a=1;
System.out.println(a==1?"等于":"不等于");
Boolean bool=false;
System.out.println(bool?"真":"假");
反编译后:
可以看到,包装类进行比较运算,是先进行拆箱成基本数据类型,然后进行运算的。
自动拆装箱有什么用
我从官网偷了个例子:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
为什么上面的代码不报错呢,因为编译时代码自动转换了一下,如下:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
所以 li集合里面存的实际上是Interger对象,而不是基础数据类型。
- 第一,方便使用,包装类中有很多方法,比如转换成其他数据类型的方法,等等
- 第二, 多态,我们都知道,所有的类都继承了Object ,而基本数据类型没有继承,所有使用包装类可以使用多态这个特性,就像上面那个例子。
自动拆装的疑惑?
一、包装类对象为什么会相等
看,a==b 为true,c==d 为false
Integer a=2;
Integer b=2;
Integer c=128;
Integer d=128;
System.out.println(a==b); //true
System.out.println(c==d); //false
操作数都是对象,“==” 比较的是引用地址,都是自动装箱。应该都是false才是,为什么是a==b是true呢?
我们知道,自动装箱是通过valueOf()方法来实现的,源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可以看出来,数值大小在low到high之间返回的是缓存中的对象,超出这个范围则是new 一个返回。low= -128 ;high如果不指定的话值为127;
很显然,2在这个范围,所以Integer.valueOf(2)的时候,返回的是缓存的对象,所以a和b其实是一个对象所以相等。
其他几个包装类中;Double与Float是直接new 一个对象返回的;Long,Short,Character与Integer类似,而Byte则是直接返回缓存中的对象,想一下Byte的取值范围就明白了;Boolean比较特殊,一共就两个值,如下:
二、什么时候会进行自动拆装箱
看一段我从某位大佬那里借鉴(偷)过来的代码:
Integer a = 1;
Integer b = 2;
Integer c = 3;
Long g = 3L;
Long h = 2L;
System.out.println(c==(a+b)); //1. true
System.out.println(g==(a+b)); //2. true
System.out.println(c.equals(a+b));//3. true
System.out.println(g.equals(a+b)); //4. false
System.out.println(g.equals(a+h));//5. true
仔细想下,为什么会这样呢?我来分析下,如果您认为我分析有误或者有疑问欢迎联系我。
- 1、为什么c==(a+b) 为true?
是因为,a+b 是进行算术运算,上文提到过,算术运算时,会拆箱成基本数据类型进行运算,那么a+b的结果也是基本数据类型,而包装类类型进行==比较时,如果有一方是基本数据类型,那么包装类类型会进行拆箱。所以c==(a+b) 比较的是数值是否相等。 结果为true - 2、为什么g==(a+b) 为true?
同1。 - 3、c.equals(a+b) 为什么为 true?
首先放一段Integer.eqquals()的源码:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
看了上面的源码就很好理解了,a和b都是Integer类型,拆箱算术运算结束后结果也是int 类型,然后equals需要的是对象,所以这里会进行装箱,还是Integer类型,然后类型判断结果为true,比较的是数值,所以结果为true。
- 4、g.equals(a+b) 为什么是false呢?
g是Long类型,我们看下Long的equals()方法;
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
看了源码很容易就知道为什么了,上面说过a+b结果为int类型,在这里自动装箱也是对应的Integer类型,Integer 类型不属于Long类型,结果为false,直接返回false,
- 5、g.equals(a+h)为什么为true?
相信你已经很明白了为什么了。
下面放出反编译后的代码,很容易就看出哪里进行了拆箱装箱。