自动装箱/拆箱是在运行时(JVM)还是编译时(编译器)完成的?
我收到了这个答案:
自动装箱通过编译器将方法调用和类型转换插入到代码中来实现。这些调用和转换在运行时进行处理。
请详细解释一下。
从Java规范中得知:
在Java编程语言中,每个表达式都有一个类型,可以从表达式的结构以及表达式中提到的字面量、变量和方法的类型推导出来。然而,在某些情况下,可能会在不合适的上下文中编写表达式。有时,这会导致在编译时出现错误。在其他情况下,上下文可能能够接受与表达式类型相关的类型;为了方便起见,而不是要求程序员明确表示类型转换,Java编程语言将表达式的类型隐式转换为其周围上下文可接受的类型。
由此,我们知道即使程序员没有指示类型转换,编译器也会接受特定的表达式。这就是为什么以下代码在编译时不会引发错误的原因。
int i = new Integer(3);
Integer j = 3;
... 在运行时,自动装箱转换如下进行:
如果 p 是 boolean 类型的值,则自动装箱转换将 p 转换为类和类型为 Boolean 的引用 r,使得 r.booleanValue() == p ...
... 在运行时,自动拆箱转换如下进行:
如果 r 是 Boolean 类型的引用,则自动拆箱转换将 r 转换为 r.booleanValue() ...
这就是在运行时确切发生的事情。
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);
}
}
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的静态类型安全所必需的。
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 fromi
and adds the object toli
. 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));
因此,转换是通过编译器将方法调用和强制类型转换插入到代码中实现的,在编译时发生但在运行时处理。