给定以下使用 Java 8 的类 Optional
:
final class Main {
public static void main(final String[] args) {
System.out.println(Optional.of("test").get());
}
}
如果我使用针对 Java 7 字节码的 Java 8 编译器编译代码:
javac -target 1.7 -source 1.7 Main.java
当我使用 Java 7 JVM 运行时,main
抛出 NoClassDefFoundError
包装 ClassNotFoundException
对于 java.util.Optional
正如预期的那样。
但是,如果我检查 Optional
的可用性使用前的类(通过反射):
final class Main {
public static void main(final String[] args) {
if (isOptionalAvailable()) {
System.out.println(Optional.of("test").get());
} else {
System.out.println("Optional not found.");
}
}
private static boolean isOptionalAvailable() {
try {
Class.forName("java.util.Optional");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
当我使用 Java 7 JVM 运行时,它没有抛出任何错误:
Optional not found.
我想知道的是,这种行为是否是 JVM 或 JLS 规范所要求的。看起来这种行为在 Oracle、IBM 和 OpenJDK 中是一致的,但我似乎无法在规范中找到任何必须延迟加载方法中本地使用的类的要求。
我浏览了 "Chapter 5. Loading, Linking, and Initializing" JVM 规范和 "15.12.4. Run-Time Evaluation of Method Invocation"在 JLS 中。
对于我的第二个示例,是否可以有一个急切加载 Optional
的 JVM 实现?即使它只存在于未使用的代码路径中?我是否遗漏了规范中需要此行为的部分,或者它只是一个常见的实现细节?
最佳答案
不保证类不会被加载。
考虑 JLS, §5.4 :
This specification allows an implementation flexibility as to when linking activities (and, because of recursion, loading) take place, provided that all of the following properties are maintained:
…
For example, a Java Virtual Machine implementation may choose a "lazy" linkage strategy, where each symbolic reference in a class or interface (other than the symbolic references above) is resolved individually when it is used. Alternatively, an implementation may choose an "eager" linkage strategy, where all symbolic references are resolved at once when the class or interface is being verified.
即使是使用惰性类加载的 HotSpot JVM,也可能会尝试比预期更早地加载类,即在未使用的代码路径之外,由于代码的微妙方面,这可能需要验证者加载类,如在 When is a Java Class loaded? 中讨论
换句话说,即使使用这个 JVM 实现,当类不存在时,对代码的小改动可能会突然导致它失败。
关于java - JVM/JLS 中是否指定永远不会加载未使用代码路径中的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69623174/