自动装箱和拆箱的概念

在 Java 中,基本数据类型(如 intdouble 等)和对应的包装类(如 IntegerDouble 等)之间可以进行自动转换,这个过程分别被称为自动装箱(Autoboxing)和自动拆箱(Unboxing)。自动装箱是指将基本数据类型自动转换为对应的包装类对象;自动拆箱则是将包装类对象自动转换为对应的基本数据类型。

实现原理

自动装箱

自动装箱是通过调用包装类的 valueOf() 方法实现的。以下是一个示例代码及对应的字节码分析:

public class AutoboxingExample {
    public static void main(String[] args) {
        int num = 10;
        Integer integerObj = num; // 自动装箱
    }
}

使用 javap -c 命令查看字节码,会发现自动装箱实际上调用了 Integer.valueOf() 方法:

Compiled from "AutoboxingExample.java"
public class AutoboxingExample {
  public AutoboxingExample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: istore_1
       3: iload_1
       4: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       7: astore_2
       8: return
}

自动拆箱

自动拆箱是通过调用包装类的 xxxValue() 方法实现的,其中 xxx 表示对应的基本数据类型。示例代码及字节码分析如下:

public class UnboxingExample {
    public static void main(String[] args) {
        Integer integerObj = 10;
        int num = integerObj; // 自动拆箱
    }
}

字节码显示自动拆箱调用了 Integer.intValue() 方法:

Compiled from "UnboxingExample.java"
public class UnboxingExample {
  public UnboxingExample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: aload_1
       7: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      10: istore_2
      11: return
}

自动发生的场景

自动装箱发生的场景

  • 赋值操作:将基本数据类型赋值给对应的包装类对象时会自动装箱。
int a = 20;
Integer b = a; // 自动装箱
  • 方法调用:当方法参数为包装类对象,而传入的是基本数据类型时会自动装箱。
public static void printInteger(Integer num) {
    System.out.println(num);
}

public static void main(String[] args) {
    int num = 30;
    printInteger(num); // 自动装箱
}

自动拆箱发生的场景

  • 赋值操作:将包装类对象赋值给对应的基本数据类型时会自动拆箱。
Integer c = 40;
int d = c; // 自动拆箱
  • 算术运算:在进行算术运算时,如果操作数中有基本数据类型和包装类对象,包装类对象会自动拆箱。
Integer e = 50;
int f = e + 10; // 自动拆箱
  • 条件判断:在条件判断语句中,如果需要基本数据类型的布尔值,包装类对象会自动拆箱。
Boolean boolObj = true;
if (boolObj) { // 自动拆箱
    System.out.println("条件为真");
}

需要注意的是,虽然自动装箱和拆箱带来了代码编写的便利,但在性能敏感的场景下,频繁的装箱和拆箱操作可能会影响性能,因为涉及到对象的创建和销毁。