Boxing and Unboxing in Java

装箱(Boxing) 和 拆箱(Unboxing)

Autoboxing 是指Java编译器在基本类型与其对应的对象包装类之间进行的自动转换。例如,将int转换为Integer,将double转换为Double,等等。如果转换方向相反,则称为Unboxing

以下是最简单的自动装箱示例:

Character ch = 'a';

本节其余示例均使用泛型。若您尚未熟悉泛型的语法,请参阅泛型章节。

考虑以下代码:

List<Integer> ints = new ArrayList<>();
for (int i = 1; i < 50; i+=2) {
    ints.add(i); 
}

尽管你向 ints 中添加的是 int 值(原始类型)而非 Integer 对象,代码仍能编译通过。由于 ints 是 Integer 对象的列表而非 int 值的列表,你可能会疑惑为何 Java 编译器未在编译时报错。编译器之所以不报错,是因为它会将i转换为Integer对象,再将该对象加入ints列表。因此编译器会在运行时将原代码转换为以下形式:

List<Integer> ints = new ArrayList<>();
for (int i = 1; i < 50; i+=2) {
    ints.add(Integer.valueOf(i)); 
}

将基本类型值(例如整型)转换为对应包装类Integer的对象称为自动装箱。当基本类型值满足以下条件时,Java编译器会应用自动装箱:

  • 作为参数传递给一个方法,该方法期望接收对应包装类的对象。
  • 赋值给一个对应包装类的变量。

考虑以下方法:

public static int sumEven(List<Integer> ints) {
    int sum = 0;
    for (Integer i: ints) {
        if (i % 2 == 0) {
            sum+=i;
        }
    }
    return sum;
}

由于取余运算符(%)和单目加运算符(+=)不适用于Integer bjects,您可能会疑惑Java编译器为何能无误编译该方法。编译器之所以不报错,是因为它会在运行时调用intValue()方法将Integer转换为int类型:

 public static int sumEven(List<Integer> ints) {
        int sum = 0;
        for (Integer i : ints) {
            if (i.intValue() % 2 == 0) {
                sum += i.intValue();
            }
        }
        return sum;
}

将包装类型Integer的对象转换为其对应的原始类型(int)值称为unboxing(拆箱)。当包装类的对象满足以下条件时,Java编译器会执行拆箱操作:

  • 作为参数传递给一个方法,该方法期望接收对应基本数据类型的值。
  • 赋值给对应基本类型的变量。

Unboxing 示例展示了其工作原理:

public class Unboxing {
    public static void main(String[] args) {
        Integer i = Integer.valueOf(-8);

        // 1. Unboxing through method invocation
        int absVal = absoluteValue(i);
        IO.println("absolute value of " + i + " = " + absVal);

        List<Double> doubles = new ArrayList<>();
        doubles.add(3.1416); // Π is autoboxed through method invocation

        // 2. Unboxing through assignment
        double pi = doubles.get(0);
        IO.println("pi = " + pi);
    }

    public static int absoluteValue(int i){
        return i < 0 ? -i : i;
    }
}

程序的输出如下:

absolute value of -8 = 8
pi = 3.1416

自动装箱和拆箱功能使开发人员能够编写更简洁的代码,从而更易于阅读。下表列出了基本类型及其对应的包装类,这些包装类被Java编译器用于自动装箱和拆箱操作:

基本类型 包装类
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double