3

我问:

自动装箱/拆箱是在运行时(JVM)还是在编译时(编译器)完成?

我收到了这个答案:

自动装箱是通过编译器在代码中插入方法调用和强制转换来实现的。这些调用和强制转换在运行时处理。

请更详细地解释。

4

4 回答 4

3

来自 Java 规范

第 5 章转换和促销

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

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

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

第 5 章转换和促销 5.1.7。拳击转换

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

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

第 5 章。转换和促销 5.1.8。拆箱转换

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

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

这正是运行时发生的事情。

于 2012-03-15T05:04:36.083 回答
1

自动装箱和拆箱是编译时过程。

我们可以通过如下所述的小测试进行验证:

例如,创建一个名为“Crap”的 Java 项目。在其中,创建一个包含以下内容的 .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。

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

public class Junk {

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

现在,构建 Junk 项目,并将 Junk.java 作为 Java 应用程序运行。它将成功运行,输出将是

大声笑..这是废话!

现在,修改 Crap.java,将 Boolean 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)
于 2013-08-15T08:17:45.507 回答
0

好吧,它说编译器会这样做。所以它发生在编译时。

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

于 2012-03-15T04:38:51.223 回答
0

Tutorials中,它说:

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

...编译器不会生成错误,因为它会Integer从. 因此,编译器在运行时将前面的代码转换为以下代码:ili

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

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

于 2022-01-18T13:45:19.823 回答