我们知道Java的基本数据类型都有对应的封装数据类型,如下:
基本数据类型 | 封装数据类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
自动装箱就是Java自动将基本数据类型值转换为封装数据类型对象;
自动拆箱就是Java自动将封装数据类型对象转换为基本数据类型值。
为什么是自动的呢?因为这里的装箱和拆箱的过程是自动完成的而不是通过人工进行转换的。
注意Java的自动拆装箱是发生在编译期,即javac编译的那一刻,而不是发生在运行期。
int n = 20;
//自动装箱
Integer m = n;
//手动装箱
Integer m1 = new Integer(2);
Integer n = new Integer(2);
//手动拆箱
int m = n.intValue();
//自动拆箱
int m1 = n;
.valueOf(int i) 发生装箱
.intValue() 发生拆箱
举个例子,并深究一下:
首先看一下,下面例子的输出结果是什么?如果你猜对了?那么你知道为什么是这样吗?
Integer num1 = 288;
Integer num2 = 288;
System.out.println(num1 == num2);
没错,答案输出就是:false
为什么两个整型值比较不相等呢?首先我们知道“==”比较两个基本类型数据时,比较的是值;而比较两个对象时,比较的是两个对象的地址;
输出结果是false,那就说明这两个对象地址不同,不是同一个对象。
首先我们看一下装箱的源码:
当我们不知道IntegerCache是什么的时候,理解这段代码:当传入的值在某个特定的范围时[IntegerCache.low,IntegerCache.high]
就返回IntegerCache.cache数组下的索引为 i+(-IntegerCache.low)的值,
否则就返回新创建的一个对象值;
如下图,IntegerCache源码,我们得知,IntegerCache是Integer类里的一个私有的静态内部类,主要包含了两个常量low=-128和high和一个cache缓存数组,cache数组会在第一次使用时初始化,
high的值可能由property配置,如果配置,区间值为[-128,high],否则为[-128,121],
当传入的值在这个区间的时候,就直接去从cache数组里直接取值
所以,这就是上面的例子输出结果为false的原因,因为不再区间范围,就会新创建对象,当然对于封装类型的对象的比较,
由于封装类型的对象都重写了equals方法,所以使用equals比较封装类型对象,其实比较的是值,而不是地址,
如果是基本数据类型和封装类型比较用“==”,则会拆箱后再去比较值。
同样,Byte,Short,Long与Integer类似,valueOf()在区间范围内,从缓存数组中取值,否则就返回新创建的对象;
Float,Double valueOf直接返回新创建的对象,Character缓存区间为[0,127];
Boolean类型因为就true和false两个值,所以 valueOf(boolean b)返回(b ? TRUE : FALSE);
注意:
因为自动装箱会隐式的创建对象,很容易生成无用对象,所以如果在一个循环体中,
一定要注意代码中避免引入不必要的自动装箱操作,否则除了会创建无用的中间对象外,还会增加GC压力,降低程序的性能。