什么是装箱?什么是拆箱?
自动装箱拆箱操作是从Java SE5开始提供的特性。
-
装箱:将基本类型用它们对应的引用类型包装起来;
-
拆箱:将包装类型转换为基本数据类型;
Java SE5之前,需要这样创建数值为10的Integer对象。
Integer i = new Integer(10);
加入自动装箱拆箱后则:
Integer i = 10;
Integer i = 10; //装箱
int n = i; //拆箱
8种基本数据类型和对应的包装器类型。
int(4字节) | Integer |
---|---|
byte(1字节) | Byte |
short(2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char(2字节) | Character |
boolean(未定) | Boolean |
自动装箱和拆箱中的问题
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);
System.out.println(i3==i4);
}
}
输出为:
true
false
导致这个问题的原因是i1和i2指向同一个Integer对象,而i3和i4指向不同的Integer对象,在用==
进行比较的过程中,使用了Integer.valueOf方法,其源码是这样的:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
基本类型的包装类的大部分都实现了常量池技术,可以看到这里对i也就是传入的int数值进行了范围限定,在传入数值在-128~IntegerCache.high之间时,不会创建新的Integer对象,而是直接指向cache中存在的对象。再来看看IntegerCache的源码:
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
可以看到这里允许我们对high即上限进行重写,但是不允许对low进行变化,默认为[-128,127]之间,所以上述代码输出一个为true一个为false。因为2进制最大数是127:是2的7次方减1,也就是127 , 而最小的数是-128:由于负数在计算机中是以其补码形式存在也就是这里是根据二进制的大小存在的。这是对内存优化的机制。
由此可以猜想,Double类型(包含Float),Boolean类型,他们的输出会怎样的。
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
false
false
可以想象,Integer类型(包括Short,Long等)他们的valueOf方法的实现是类似的,而浮点数的个数由于是无限的,所以不能采用这样的形式来优化,因此Double,Float会直接创建两个不同对象。而Boolean呢?
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
true
true
查看他的源代码发现:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
public static final Boolean TRUE = new Boolean(true);
/**
* The <code>Boolean</code> object corresponding to the primitive
* value <code>false</code>.
*/
public static final Boolean FALSE = new Boolean(false);`
Boolean类型相当于直接将true和false的值直接传递过去了。
Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。
- 第一种方式不会触发自动装箱的过程;而第二种方式会触发;
- 在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。
需要注意的是,当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。
参考:https://www.cnblogs.com/dolphin0520/p/3780005.html