包装类(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); // falseInteger integer3 = 1;Integer integer4 = 1;System.out.println(integer3 == integer4); // true
包装类与基本数据类型的选择
《阿里巴巴 Java 开发手册》有以下规定:
- 【强制】所有的 POJO 类属性必须为包装数据类型
- 【强制】RPC 方法的返回值和参数必须使用包装数据类型
- 【推荐】所有的局部变量使用基本数据类型
