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

标签 java jvm jls

给定以下使用 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/

相关文章:

java - 从 JVM 崩溃日志中的堆栈跟踪获取行号

java - 具体获取方法还是一般获取方法?

java - <![CDATA ["' "]]> 返回两个结果。某些应用程序版本打印 "' ",另一个应用程序版本打印 '.为什么?

尽管设置了 -Xmx300m -Xss512k -XX :MetaspaceSize=100M?,Java 内存仍超过 512mb

java - 在静态初始值设定项外部声明的类型变量在静态初始值设定项内

java - 非 volatile 字段+来自另一个线程的第一个对象访问(java)

java - renameTo 不适用于重命名文件

java - 是否可以在不使用其他库的情况下连接到 SFTP 存储库?

java - 删除用于简单字母表的 ascii

java - 限定名称和字段访问表达式有什么区别?