Java 何时在运行时查找 Jar 文件的依赖项?
在一开始就运行它?
当它尝试初始化一个具有某种依赖性的类时?
还是其他时间?
未指定加载 .class 文件的确切时间。main
如您所知,甚至在方法开始执行之前,类路径中的所有类文件都可能被加载。
Java 唯一指定的是何时初始化一个类,这与加载它完全不同。
Java 语言规范,§12.3说(我的重点):
该规范允许在何时发生链接活动(以及由于递归,加载)时实现灵活性,前提是尊重语言的语义,在初始化之前对类或接口进行完全验证和准备,并且在链接过程中检测到的错误会在程序中的某个点引发,在该点程序采取了可能需要链接到错误中涉及的类或接口的某些操作。
例如,实现可以选择单独解析类或接口中的每个符号引用,仅在使用时(延迟或延迟解析),或者在验证类时一次性解析它们(静态解析)。这意味着在某些实现中,在初始化类或接口之后,解析过程可能会继续。
现在,规范说 JVM可以做一系列事情,但很明显,任何给定的 JVM都可以做一件特定的事情。Marko 的回答说“甚至在main
方法开始执行之前,类路径中的所有类文件都可能被加载”,他是对的,但事实是实际上没有 JVM 会这样做。
我相信 Sun JVM 中实际发生的事情是尽可能晚地加载内容。每当一个类被初始化时,它所引用的任何类都需要被加载和验证,但在它们自己被实际使用之前不需要初始化。我很欣赏这不是一个非常详细或权威的答案。
我很确定它发生在编译时。如果不满足所有要求和依赖项,您将无法获得代码的编译版本。
在编译jar的情况下,我准备了两个类:
public class Test {
public static void main(String[] args) {
System.out.println("T1: Hello world");
Test2.greet();
}
}
和:
public class Test2 {
public static void greet() {
System.out.println("T2: Hello world");
}
}
第一次尝试运行导出的项目:
$ java -jar test.jar
T1: Hello world
T2: Hello world
然后,从我的 jar 文件中删除 Test2.class 然后再次运行它:
$ java -jar test-mod.jar
T1: Hello world
Exception in thread "main" java.lang.NoClassDefFoundError: Test2
at Test.main(Test.java:6)
Caused by: java.lang.ClassNotFoundException: Test2
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
T1 测试通过,然后出现 NoClassDefFoundError 异常。因此,回答您的问题:将在运行时检查依赖项。