2

考虑这个(半伪)代码:

private static final File file = new File("./archive.jar");
private static URLClassLoader classLoader;

public static void main(final String[] args) {
    try {
        classLoader = new URLClassLoader(new URL[] { file.toURI().toURL() });
        Method mainMethod = classLoader.loadClass("main class").getDeclaredMethod("main", String[].class);
        mainMethod.setAccessible(true);
        mainMethod.invoke(null, (Object) new String[] { "-arguments" });
    } catch(Exception e) {
        e.printStackTrace();
    }
}

...以及 Eclipse IDE 中的这两个项目设置:

第一个项目设置。 第二个项目设置。

提供的代码不会从 JAR 文件中导入任何内容,但行为不同。它有什么不同?好吧,在使用第一个项目设置时,本网站的主题会引发错误:

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
Caused by: java.lang.StackOverflowError
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)

该行发生的错误:

mainMethod.invoke(null, (Object) new String[] { "-arguments" });

但是,在使用第二个项目设置(其中 JAR 是构建路径的一部分)时不会发生错误。除此之外,代码在使用第一个项目设置时根本不起作用。我知道当它正常工作时会发生什么,第一个项目设置不会发生这种情况,但第二个项目设置会发生这种情况。另一件值得一提的事情是,只有当 JAR 文件位于 Eclipse 中的 Order 和 Exports 列表的顶部时,代码才会起作用:

订单和出口清单。

为什么会这样?如果没有从 JAR 导入,为什么它需要成为构建路径的一部分才能工作?类加载器根据实际文件使用它,因此它是否与项目的构建路径相关联无关紧要。

4

1 回答 1

3

StackOverflowError 通常表示调用循环。在这种情况下,我认为 JVM 可能会四处寻找它需要的东西,例如检查它试图链接的类是否有效。

链接是运行方法所必需的,并且涉及符号引用的验证和解析。

要进一步了解在没有库的情况下出了什么问题,有必要查看主类的代码以了解它引用的内容。

在 Java 中不要太重视 import。它只允许您使用类名而不完全限定它们:ArrayList,而不是 java.util.ArrayList。

于 2012-11-05T05:24:23.903 回答