包装类(wrappers)
type | byte | short | int | long | float | double | char | boolean |
---|---|---|---|---|---|---|---|---|
wrapper | Byte | Short | Integer | Long | Float | Double | Character | Boolean |
继承自 Number 类 | ||||||||
实现了 Serializable 和 Comparable 接口 |
- 所有包装类都是 immutable 的(不可修改,不可继承)。
- 包装类应该使用
equals()
方法判断是否相等。 - 包装类可以为
null
,但自动拆箱时会抛出NullPointerException
.
语法糖
Integer integer = 1; // 装箱
int i = integer; // 拆箱
对以上代码进行反编译,结果如下所示:
Integer integer = Integer.valueOf(1);
int i = integer.intValue();
从上面反编译的代码可以看出,int 类型的自动装箱都是通过 Integer.valueOf()
方法来实现的,Integer 的自动拆箱都是通过 Integer.intValue
来实现的。
事实上,自动装箱都是通过包装类的 valueOf()
方法实现的,自动拆箱都是通过包装类的 xxxValue()
方法实现的。
缓存机制
在 Byte
、 Short
、 Integer
、 Long
、 Character
五个包装类内,都有一个静态内部类,用于维护一个包装类对象缓存数组。当对应的基本数据类型在自动装箱时,会先判断对应的包装类是否在缓存数组内,如果在,则复用该数组缓存的对象,否则生成一个新的对象。
下面以 Integer
类为例,展示相应的源码:
public final class Integer extends Number implements Comparable<Integer> {
// 静态内部类
private static class IntegerCache {
static final Integer cache[]; // 缓存数组
...
}
// 自动装箱
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
}
Boolean
也有类似的缓存机制,但和上述提到的 5 个包装类不同的是, Boolean
并无静态内部类和缓存数组,而是直接定义了两个静态常量,并在自动装箱时进行判断,源码如下所示:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
Float
和 Double
无类似的缓存机制。各包装类的缓存范围如下表所示:
包装类 | 缓存范围 |
---|---|
Byte | ALL |
Short | -128 - 127 |
Integer | -128 - 127 |
Long | -128 - 127 |
Character | \u0000 - \u007F(0 - 127) |
Boolean | ALL |
Float | 无 |
Double | 无 |
需要再次强调的是:只有在自动装箱时(即调用 valueOf()
方法),相应的缓存机制才会生效,通过 new 关键字会创建新的包装类对象。
Integer integer1 = new Integer(1);
Integer integer2 = new Integer(1);
System.out.println(integer1 == integer2); // false
Integer integer3 = 1;
Integer integer4 = 1;
System.out.println(integer3 == integer4); // true
包装类与基本数据类型的选择
《阿里巴巴 Java 开发手册》有以下规定:
- 【强制】所有的 POJO 类属性必须为包装数据类型
- 【强制】RPC 方法的返回值和参数必须使用包装数据类型
- 【推荐】所有的局部变量使用基本数据类型