自动装箱/拆箱在Java中是如何工作的?

2022-09-02 10:25:02

从 JDK 5.0 开始,Java 中引入了自动装箱/拆箱。这个技巧既简单又有用,但是当我开始测试包装器类和基元类型之间的不同转换时,我对自动装箱的概念在Java中的工作方式感到非常困惑。例如:

拳击

int intValue = 0;
Integer intObject = intValue;
byte byteValue = 0;
intObject = byteValue; // ==> Error

在尝试不同的情况(, , , )后,编译器接受的唯一情况是当情感运算符右侧的值的类型为 。当我查看源代码内部时,我发现它只实现了一个带有参数的构造函数。shortlongfloatdoubleintInteger.classint

所以我的结论是,自动装箱的概念是基于包装类中实现的构造函数。我想知道这个结论是否属实,或者自动拳击是否使用了另一个概念?

拆 箱

Integer intObject = new Integer(0);
byte byteValue = intObject; // ==> Error (the same Error with short)
int intValue = intObject; 
double doubleValue = intObject;

我关于取消装箱的结论是,包装类给出了由对象包装在相应类型中的值( ==>),然后编译器使用转换基元类型的常用规则( => = > = > = > = > )。我想知道这个结论是否正确,或者自动开箱是否使用了另一个概念?Integerintbyteshortintlongfloatdouble


答案 1

如有疑问,请检查字节码:

Integer n = 42;

成为:

0: bipush        42
2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1      

因此,实际上,valueOf() 与构造函数相反(其他包装类也是如此)。这是有益的,因为它允许缓存,并且不会强制在每次装箱操作上创建新对象。

反之亦然:

int n = Integer.valueOf(42);

它变成:

0: bipush        42
2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: invokevirtual #22                 // Method java/lang/Integer.intValue:()I
8: istore_1      

即使用intValue()(同样,它也适用于其他包装器类型)。这真的是所有自动(取消)拳击归结为。

您可以分别在 JLS §5.1.7 和 JLS §5.1.8 中阅读有关装箱和取消装箱转换的信息。


答案 2

这种混淆可以通过使用javac-XD-printflat的开关来清除,这在这样的情况下是非常有帮助的。因此,要解开拳击和拆箱的奥秘,您可以编写一个简单的程序,如下所示:

import java.util.*;

public class Boxing{
  public static void main(String[] args){
    Double d1 = 10.123;
    Float  f1 = 12.12f;
    Long   l1 = 1234L;
    Integer i1 = 55555;
    Short   s1 = 2345;
    Byte    b1 = 89;

    double d2 = d1;
    float  f2 = f1;
    long   l2 = l1;
    int    i2 = i1;
    short  s2 = s1;
    byte   b2 = b1;
  }
} 

现在我们将上述文件编译为:

javac -XD-printflat -d src/ Boxing.java

此命令的输出是一个java文件,其中删除了所有语法糖(通用类型,增强的循环,在这种情况下是装箱 - 解箱等)。下面是输出

import java.util.*;

public class Boxing {

    public Boxing() {
        super();
    }

    public static void main(String[] args) {
        Double d1 = Double.valueOf(10.123);
        Float f1 = Float.valueOf(12.12F);
        Long l1 = Long.valueOf(1234L);
        Integer i1 = Integer.valueOf(55555);
        Short s1 = Short.valueOf(2345);
        Byte b1 = Byte.valueOf(89);
        double d2 = d1.doubleValue();
        float f2 = f1.floatValue();
        long l2 = l1.longValue();
        int i2 = i1.intValue();
        short s2 = s1.shortValue();
        byte b2 = b1.byteValue();
    }
}

这就是java如何进行拳击解箱。使用 valueOf 和 ***Value 方法。


推荐