0

我读了JLS 第 12 章。执行所以它说关于解决方案

解析是检查从 Test 到其他类和接口的符号引用的过程,方法是加载提到的其他类和接口并检查引用是否正确。

在初始链接时,解析步骤是可选的。实现可以从很早就被链接的类或接口解析符号引用,甚至可以递归地解析来自被进一步引用的类和接口的所有符号引用。...

一个实现可能会选择仅在积极使用符号引用时才解析它;对所有符号引用一致使用此策略将代表“最懒惰”的解决形式。在这种情况下,如果 Test 有多个对另一个类的符号引用,那么这些引用可能会在使用时一次解析一个,或者如果在程序执行期间从未使用过这些引用,则可能根本不解析。

例如,实现可以选择单独解析类或接口中的每个符号引用,仅在使用时(延迟或延迟解析),或者在验证类时一次性解析它们(静态解析)。这意味着在某些实现中,在初始化类或接口之后,解析过程可能会继续。

所以我的问题是我是否可以选择/强制使用延迟初始化?也许它需要编写一个自定义类加载器?或者,启动时类加载器中的 ClassNotFoundException 可能会被忽略?

我有条件地创建了一个对象,main其中不应该实际发生,并且 jar 中缺少相应的类。但是甚至在开始执行之前就NoClassDefFound被抛出。main

4

3 回答 3

2

NoClassDefFoundError错误:

如果 Java 虚拟机或ClassLoader实例尝试加载类的定义(作为正常方法调用的一部分或作为使用new表达式创建新实例的一部分)并且找不到类的定义,则抛出此异常。

该错误与实例化相关类的实例无关。因此,对于您的示例,如果“外部”类为该类型定义了一个字段,则可能就足够了。无法加载包含 main 的类,因为它依赖于运行时类路径中不可用的类型。

如果有疑问,请查看您的导入语句并删除您要动态加载的类的 import * )。然后尝试摆脱错误标记,而无需再次为该类添加导入。

* ) - 我假设这个动态加载的类位于不同的包中,您需要导入它。

于 2012-12-18T09:13:55.380 回答
2

您不能使用 Oracle 的 JVM。

根据文档,类加载器不能推迟类的加载。链接的顺序和时间是特定于实现的。AFAIK 大多数 JVM 选择尽早链接,有些甚至在编译时链接(参见 Excelsior JET 示例)。

于 2012-12-18T09:15:56.110 回答
1

考虑这个

class Test2 {
}

public class Test1 {
    static Test2 test2;

    public static void main(String[] args) {
        System.out.println("Test1");
        test2 = new Test2();
    }
}

我编译它,删除 Test2.class 并运行java -cp . Test1输出

    Test1
    Exception in thread "main" java.lang.NoClassDefFoundError: Test2
        at Test1.main(Test1.java:9)
    Caused by: java.lang.ClassNotFoundException: Test2
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
......

在我看来,这意味着 JVM 依赖解析默认是惰性的。JVM 直到第一次使用才注意到 Test2.class 丢失了。

于 2012-12-18T09:33:12.727 回答