简单记录一下自动拆装箱原理以及使用过程中要注意的坑。
目录
1、Java基本数据类型
基本数据类型和与之对应的包装类型:
boolean、byte、char、float、int、long、short、double
Boolean、Byte、Character、Float、Integer、Long、Short、Double
2、自动拆箱、自动装箱
在JDK1.5之前,进行拆箱和装箱操作时,需要开人员通过代码来实现的,JDK1.5之后,Java出现一个新特性,可以自动对基本数据类型和包装类型进行转换,即:自动拆箱、自动装箱。
2.1 自动装箱
// 自动装箱 相当于 Integer a = Integer.valueOf(100);
Integer a = 100;
Integer a = 100; 这个语句,通过deBug可以发现,底层执行了Integer的valueOf()方法,该方法返回了一个Integer对象;
源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
2.2 自动拆箱
Integer b = new Integer(100);
// 自动拆箱 相当于 int c = b.intValue();
int c = b;
这个语句,通过deBug可以发现,底层执行了Integer的intValue()方法,该方法返回了一个int基本数据类型;
源码:
public int intValue() {
return value;
}
3、避坑问题
如下代码:
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // 结果:true
Integer x = 200;
Integer y = 200;
System.out.println(x == y); // 结果:false
System.out.println(x.intValue() == y.intValue()); // 结果:ture
为什么中段代码 Integer x = 200;Integer y = 200; System.out.println(x == y); 执行结果是false呢?
因为Integer x = 200;进行了自动装箱,在自动装箱过程中,底层执行了Integer的valueOf()方法,该方法会判断值的大小,如果在-128至127这个范围,就返回缓存里面的值,否则就会new一个Integer对象。
部分源码:
// Integer的内部类
private static class IntegerCache {
static final int low = -128;
static final int high;
// 存放Integer对象
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
// 忽略其他代码.....................
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
// 忘cache里面存放Integer对象
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
// 判断i的是否在缓存里存在,不存在就创建一个新的对象返回,存在就返回缓存里面的对象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
通过源码可以看出,如果自动装箱值的范围不在缓存内,就重新new一个对象,不同的对象使用==判断自然是为false的,因为内存地址是不一样的;
所以,当我们使用包装类型进行比较的时候,最好使用intValue()方法,如下:
Integer x = 200;
Integer y = 200;
System.out.println(x.intValue() == y.intValue()); // 结果:ture
intValue()方法底层返回的是int基本数据类型,所以可以使用==相比较,当然,包装类型使用equals()方法进行比较也是可以的,Integer的equals方法同样是调用了intValue方法获取int类型值再进行比较,源码:
// Integer的equals方法
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
不仅仅是int和Integer,其他类型数据也类似,比如看看long和Long的源码,都是同样的原理。