自动拆箱和装箱
1. 基本类型对应的包装类型
8种基本类型对应的包装类型如下图所示:
| 基本类型 | 位数 | 字节 | 默认值 | 包装类型 |
|---|---|---|---|---|
| byte | 8 | 1 | 0 | Byte |
| short | 16 | 2 | 0 | Short |
| int | 32 | 4 | 0 | Integer |
| long | 64 | 8 | 0L | Long |
| float | 32 | 4 | 0f | Float |
| double | 64 | 8 | 0d | Double |
| char | 16 | 2 | 'u0000' | Character |
| boolean | 1 | 未定 | false | Boolean |
基本类型存储的是具体的值,而包装类型存储的是对象的引用,显然基本类型比包装类型更加简洁和高效。
那么,为什么要引入包装类型呢?区别如下:
-
包装类型可以为null,而基本类型不可以。在某些情况下,比如从数据库中查询某个学生的成绩,有可能查询到的结果是null,基本类型是无法接收的,只能使用包装类型。
-
包装类型可以用于集合和泛型,而基本类型不可以。有些朋友可能会有疑惑,我们在往集合对象里添加基本类型时,也没有报错啊?其实这是系统自动将基本类型装箱成包装类型,然后放入到集合中,所以本质上集合存储的是包装类型。而我们如果想使用泛型对集合进行限定时,用基本类型就没法办到了,例子如下:
int i = 10; List list = new ArrayList(); list.add(i);//系统会自动将i装箱为Integer类型的对象然后再存入list集合中 System.out.println(list); // [10] //使用基本类型到泛型中 List<int> list = new ArrayList<int>();//编译报错
2. 自动装箱和拆箱
- 装箱:将基本类型用它们对应的引用类型包装起来;
- 拆箱:将包装类型转换为基本数据类型;
在 Java SE5 之前,开发人员要手动进行装拆箱。
Integer i = new Integer(100); // 手动装箱
int n = i.intValue(); // 手动拆箱
Java SE5 提供了自动装箱与自动拆箱的功能
Integer i = 100; // 自动装箱,等价于 Integer i = Integer.valueOf(100);
int n = i; // 自动拆箱,等价于 int n = i.intValue();
3. 缓存池
3.1 包装类型的缓存范围
| 包装类型 | 缓存范围 |
|---|---|
| Byte | -128~127 |
| Short | -128~127 |
| Integer | -128~127 |
| Long | -128~127 |
| Float | 数量无限,无法缓存 |
| Double | 数量无限,无法缓存 |
| Character | 0~127 |
| Boolean | True和False两个静态常量 |
上一节中提到了手动装箱和自动装箱的两种方式,那么他们有什么区别呢?
Integer i = new Integer(100); // 手动装箱每次都会新建一个对象
Integer i = Integer.valueOf(100);//查看valueOf方法的源码可知,自动装箱时,会去IntegerCache缓存池中查找值是否存在缓存池中,存在则返回。所以如果自动装箱的值在缓存池范围内,多次调用会取得同一个对象的引用。
valueOf方法和IntegerCache缓存池源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
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() {}
}
4. 面试中容易出错的点
下面程序的输出结果是什么?
public static void main(String[] args) {
Integer a = 2;
Integer a1 = new Integer(2);
Integer a2 = new Integer(2);
Integer b = 3;
Integer b1 = new Integer(3);
Integer c = 5;
Integer d = 5;
Integer e = 223;
Integer f = 223;
Long g = 5L;
Long h = 3L;
System.out.println(a1==a2); //false,a1和a2都是新建的Integer对象,引用的内存地址不同
System.out.println(a1.equals(a2)); //true,a1和a2都是新建的Integer对象,引用的内存地址不同,但是值相同
System.out.println(c==d); //true,自动装箱,都从缓存池中获取同一对象,引用的内存地址相同
System.out.println(c.equals(d)); //true,自动装箱,都从缓存池中获取同一对象,引用的内存地址相同,值也相同
System.out.println(c==(a+b)); //true,==号右边操作数为表达式,自动拆箱,比较的是数值
System.out.println(c.equals(a+b)); //true,对于包装器类型,equals方法并不会进行类型转换。a+b自动拆箱装箱后,转换成Integer类型,值也与C相等
System.out.println(e==f); //false,自动装箱,数值超出缓存池缓存范围,新建Integer对象,引用的内存地址不同
System.out.println(e.equals(f)); //true,自动装箱,数值超出缓存池缓存范围,新建Integer对象,引用的内存地址不同,但是值相同
System.out.println(g==(a+b)); //true,==号右边操作数为表达式,自动拆箱,比较的是数值
System.out.println(g.equals(a+b)); //false,对于包装器类型,equals方法并不会进行类型转换。a+b自动拆箱装箱后,转换成Integer类型,Long类型和Integer类型无法比较数值,返回false
System.out.println(g.equals(a+h)); //true,对于包装器类型,equals方法并不会进行类型转换。a+h自动拆箱装箱后,转换成Long类型,与g比较后数值相等,返回true
}
附程序反编译代码做参考
public static void main(String[] var0) {
Integer var1 = Integer.valueOf(2);
Integer var2 = new Integer(2);
Integer var3 = new Integer(2);
Integer var4 = Integer.valueOf(3);
new Integer(3);
Integer var6 = Integer.valueOf(5);
Integer var7 = Integer.valueOf(5);
Integer var8 = Integer.valueOf(223);
Integer var9 = Integer.valueOf(223);
Long var10 = Long.valueOf(5L);
Long var11 = Long.valueOf(3L);
System.out.println(var2 == var3);
System.out.println(var2.equals(var3));
System.out.println(var6 == var7);
System.out.println(var6.equals(var7));
System.out.println(var6.intValue() == var1.intValue() + var4.intValue());
System.out.println(var6.equals(Integer.valueOf(var1.intValue() + var4.intValue())));
System.out.println(var8 == var9);
System.out.println(var8.equals(var9));
System.out.println(var10.longValue() == (long)(var1.intValue() + var4.intValue()));
System.out.println(var10.equals(Integer.valueOf(var1.intValue() + var4.intValue())));
System.out.println(var10.equals(Long.valueOf((long)var1.intValue() + var11.longValue())));
}
浙公网安备 33010602011771号