JVM/JLS 中是否指定永远不会加载未使用的代码路径中的类?

sti*_*kj1 3 java jvm jls

给出使用 Java 8 的以下类Optional

\n
final class Main {\n    public static void main(final String[] args) {\n        System.out.println(Optional.of("test").get());\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果我使用针对 Java 7 字节码的 Java 8 编译器编译代码:

\n
javac -target 1.7 -source 1.7 Main.java\n
Run Code Online (Sandbox Code Playgroud)\n

当我使用 Java 7 JVM 运行时,会按预期main抛出一个NoClassDefFoundError包装 a 。ClassNotFoundExceptionjava.util.Optional

\n

Optional但是,如果我在使用该类之前(通过反射)检查该类的可用性:

\n
final class Main {\n    public static void main(final String[] args) {\n        if (isOptionalAvailable()) {\n            System.out.println(Optional.of("test").get());\n        } else {\n            System.out.println("Optional not found.");\n        }\n    }\n\n    private static boolean isOptionalAvailable() {\n        try {\n            Class.forName("java.util.Optional");\n            return true;\n        } catch (ClassNotFoundException e) {\n            return false;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当我使用 Java 7 JVM 运行时,它不会抛出任何错误:

\n
Optional not found.\n
Run Code Online (Sandbox Code Playgroud)\n

我\xe2\x80\x99m 试图找出 JVM 或 JLS 规范是否需要此行为。Oracle、IBM 和 OpenJDK 之间的行为似乎是一致的,但我似乎无法在规范中找到任何要求方法中本地使用的类必须延迟加载的要求。

\n

我查阅了JVM 规范的“第 5 章:加载、链接和初始化”和JLS 中的“15.12.4. 方法调用的运行时评估” 。

\n

对于我的第二个例子,是否有一个 JVM impl 会急切地加载Optional,即使它只存在于未使用的代码路径中?我是否缺少规范中需要此行为的部分,或者它只是一个常见的实现细节?

\n

Hol*_*ger 5

无法保证该类不会被加载。

\n

考虑JLS,\xc2\xa0\xc2\xa75.4

\n
\n

该规范允许在链接活动(以及由于递归、加载)发生时实现灵活性,前提是维护以下所有属性:

\n

\xe2\x80\xa6

\n

例如,Java虚拟机实现可以选择“惰性”链接策略,其中类或接口中的每个符号引用(除了上面的符号引用之外)在使用时单独解析。或者,实现可以选择“热切”链接策略,其中在验证类或接口时立即解析所有符号引用。

\n
\n

即使使用延迟类加载的 HotSpot\xc2\xa0JVM 也可能会尝试比预期更早加载类,即在未使用的代码路径之外,由于代码的微妙方面,这可能需要验证程序加载类,如下所示在何时加载 Java 类?

\n

换句话说,即使使用此 JVM 实现,当类不存在时,对代码的微小更改也可能会突然使其失败。

\n