深入解释自动装箱的概念

3
我问:
自动装箱/拆箱是在运行时(JVM)还是编译时(编译器)完成的?
我收到了这个答案:
自动装箱通过编译器将方法调用和类型转换插入到代码中来实现。这些调用和转换在运行时进行处理。
请详细解释一下。

你对它有什么不理解的地方? - Hunter McMillen
我可以更详细地解释,但我不知道哪一部分不清楚。你知道什么是自动装箱吗? - Jochen
4个回答

3

从Java规范中得知:

第5章 转换和提升

在Java编程语言中,每个表达式都有一个类型,可以从表达式的结构以及表达式中提到的字面量、变量和方法的类型推导出来。然而,在某些情况下,可能会在不合适的上下文中编写表达式。有时,这会导致在编译时出现错误。在其他情况下,上下文可能能够接受与表达式类型相关的类型;为了方便起见,而不是要求程序员明确表示类型转换,Java编程语言将表达式的类型隐式转换为其周围上下文可接受的类型。

由此,我们知道即使程序员没有指示类型转换,编译器也会接受特定的表达式。这就是为什么以下代码在编译时不会引发错误的原因。

int i = new Integer(3);
Integer j = 3;

第五章 转换和提升 5.1.7 自动装箱转换

... 在运行时,自动装箱转换如下进行:

如果 p 是 boolean 类型的值,则自动装箱转换将 p 转换为类和类型为 Boolean 的引用 r,使得 r.booleanValue() == p ...

第五章 转换和提升 5.1.8 自动拆箱转换

... 在运行时,自动拆箱转换如下进行:

如果 r 是 Boolean 类型的引用,则自动拆箱转换将 r 转换为 r.booleanValue() ...

这就是在运行时确切发生的事情。


1
自动装箱和拆箱是编译时过程。
我们可以通过下面描述的小测试来验证:
创建一个Java项目,比如名为'Crap'。在里面,创建一个带有以下内容的.java文件:
public class Crap {

    private Boolean crap;

    public Boolean getCrap() {
        return crap;
    }

    public void setCrap(Boolean crap) {
        System.out.println("lol.. this is crap!!");
        this.crap = crap;
    }
}

构建该项目并将其导出为jar文件,例如crap.jar。

现在创建另一个Java项目,例如名为'Junk'。将crap.jar文件添加到此项目的类路径中,然后创建一个包含以下内容的.java文件:

public class Junk {

    public static void main(String[] args) {
        Crap crap = new Crap();
        crap.setCrap(true);
    }
}

现在,构建Junk项目,并将Junk.java作为Java应用程序运行。它将成功运行,输出将是 lol.. 这太糟糕了!!
现在,修改Crap.java,将布尔值crap修改为小写的boolean以及相应的getter和setter。代码将如下所示:
public class Crap {

    private boolean crap;

    public boolean getCrap() {
        return crap;
    }

    public void setCrap(boolean crap) {
        System.out.println("lol.. this is crap!!");
        this.crap = crap;
    }
}

再次构建此项目并将其导出为crap.jar。将该crap.jar文件放入Junk项目的类路径中(并从其类路径中删除先前的jar文件)。

现在,如果您尝试将Junk.java作为Java应用程序运行,则会收到以下堆栈跟踪:

Exception in thread "main" java.lang.NoSuchMethodError: crap.Crap.setCrap(Ljava/lang/Boolean;) at junk.Junk.main(Junk.java:9)

0

好的,它说编译器会这样做。因此,它发生在编译时。

这是确保Java的静态类型安全所必需的。


0
教程中,它说:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
    li.add(i);

... The compiler does not generate an error because it creates an Integer object from i and adds the object to li. Thus, the compiler converts the previous code to the following at runtime:

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

因此,转换是通过编译器将方法调用和强制类型转换插入到代码中实现的,在编译时发生但在运行时处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接