ClassLoader:可能配置为使用延迟而非静态解析?

时间:2012-12-18 08:51:52

标签: java jvm classloader

我看过JLS Chapter 12. Execution,所以它说的是分辨率

  

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

     

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

     

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

     

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

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

我在main中有条件创建一个对象,它实际上永远不会发生,并且jar中缺少相应的类。但是NoClassDefFoundmain开始执行之前就被抛出了。{/ p>

3 个答案:

答案 0 :(得分:2)

NoClassDefFoundError错误:

  

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

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

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

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

答案 1 :(得分:2)

你不能使用Oracle的JVM。

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

答案 2 :(得分: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丢失了。