我问:
自动装箱/拆箱是在运行时(JVM)还是在编译时(编译器)完成?
我收到了这个答案:
自动装箱是通过编译器在代码中插入方法调用和强制转换来实现的。这些调用和强制转换在运行时处理。
请更详细地解释。
我问:
自动装箱/拆箱是在运行时(JVM)还是在编译时(编译器)完成?
我收到了这个答案:
自动装箱是通过编译器在代码中插入方法调用和强制转换来实现的。这些调用和强制转换在运行时处理。
请更详细地解释。
来自 Java 规范
用 Java 编程语言编写的每个表达式都有一个类型,可以从表达式的结构以及表达式中提到的文字、变量和方法的类型推导出来。但是,可以在表达式类型不合适的上下文中编写表达式。在某些情况下,这会导致编译时出错。在其他情况下,上下文可能能够接受与表达式类型相关的类型;为方便起见,Java 编程语言不要求程序员显式指示类型转换,而是执行从表达式类型到其周围上下文可接受的类型的隐式转换。
从这里,我们知道即使程序员没有指明类型转换,编译器也会接受特定的表达式。这就是为什么以下代码不会在编译时引发错误的原因。
int i = new Integer(3);
Integer j = 3;
...在运行时,装箱转换进行如下:
如果 p 是布尔类型的值,则装箱转换将 p 转换为类和布尔类型的引用 r,使得 r.booleanValue() == p ...
...在运行时,拆箱转换进行如下:
如果 r 是 Boolean 类型的引用,则拆箱转换将 r 转换为 r.booleanValue() ...
这正是运行时发生的事情。
自动装箱和拆箱是编译时过程。
我们可以通过如下所述的小测试进行验证:
例如,创建一个名为“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)
好吧,它说编译器会这样做。所以它发生在编译时。
这是确保 Java 的静态类型安全所必需的。
在Tutorials中,它说:
List<Integer> li = new ArrayList<>(); for (int i = 1; i < 50; i += 2) li.add(i);
...编译器不会生成错误,因为它会
Integer
从. 因此,编译器在运行时将前面的代码转换为以下代码:i
li
List<Integer> li = new ArrayList<>(); for (int i = 1; i < 50; i += 2) li.add(Integer.valueOf(i));
因此,通过将方法调用和强制转换(由编译器)插入到代码中来实现的转换发生在编译时,但在运行时进行处理。