Java为每种基本数据类型都提供了对应的包装器类型。
基本数据类型 | 包装类 | 基本数据类型 | 包装类 |
---|---|---|---|
byte | Byte | float | Float |
short | Short | double | Double |
int | Integer | boolean | Boolean |
long | Long | char | Character |
Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,不需要使用new 关键字,只需要这样就可以了:
Integer i = 100;
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。其中,装箱过程是通过调用包装类的valueOf方法实现的,而拆箱过程是通过调用包装类的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。上段代码即自动调用了Integer的valueOf()方法。包装类的自动装拆箱还有一个容易被忽略的问题,即包装类的cache数组。
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);
// 大于127,新建对象。
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6);
以上代码的输出结果有些出人意料。true false。
可能会有同学感到疑惑,两段代码似乎没什么区别,为什么输出结果大相径庭。其实答案就在包装类的valueOf()方法中。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从源码中可以得出,当Integer类的valueOf方法被调用时并不会直接new一个对象,而是首先对传入参数的值做了一个判断,决定了是否要从IntegerCache数组中获取返回值。下面我们一下看IntegerCache是什么。
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() {}
}
IntegerCache是一个静态内部类,其维护了一个Integer数组,且数组长度微256,数组元素是尤其下标值封装的一个Integer对象。当Integer类的valueOf方法被调用时,程序首先会判断IntegerCache.cache数组中是否已存在同值的Integer对象,若存在,则直接从中获取返回,若不存在,直接新建Integer。
由此,就不难理解为什么分别新建两个值为127和值为128的Integer对象,“==”运算结果不一样了。值为127时,两次自动装箱的结果引用实际为同一对象,而参数值为128时,则是新建了两个不同的对象。Byte、Short、Integer、Long的cache的取值范围均为-128-127;Character包装类中cache的取值范围为0-127.
注意:当使用的new 关键字新建对象而不是自动装箱的情况下,程序不会从IntegerCache中获取,无论参数值是多少,都是新建的不同的对象。
Integer i3 = new Integer(100);
Integer i4 = new Integer(100);
System.out.println(i3 == i4);
输出结果为false.