从动态加载的jar文件中加载具有超类的Java类

时间:2016-10-16 08:32:48

标签: java jar jvm classloader dynamic-class-loaders

我正在尝试从动态加载的jar文件中加载类。目前我可以加载一个不扩展到根类Object以外的类的类,但是我无法加载扩展自定义类的类。我的问题的详细描述如下。

在项目A中,有一个类A:

class A {
}

在项目B中,有一个类B1和一个类B2,如:

class B1 {
}

class B2 extends A {
}

我将项目A导出到a.jar,将项目B导出到b.jar。测试代码是:

File f = new File("Z:\\Jars\\b.jar");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { f.toURL() },
        System.class.getClassLoader());

Class<?> classB1 = (Class<?>) urlClassLoader.loadClass("b.B1");
System.out.println("B1 is loaded");

Class<?> classB2 = (Class<?>) urlClassLoader.loadClass("b.B2");
System.out.println("B2 is loaded");

类B1已成功加载,但由于类a未找到类B2,因此未找到例外:

java -cp a.jar;b.jar; a.Main
B1 is loaded
Exception in thread "main" java.lang.NoClassDefFoundError: a/A
Caused by: java.lang.ClassNotFoundException: a.A
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 12 more

如何解决此问题? 感谢。

PS。通过包含a.jar,可以加载B2类但未通过以下测试:

Class<A> classB2 = (Class<A>) urlClassLoader.loadClass("b.B2");
A ab2 = classB2.newInstance();

第一行很好,但第二行触发了以下异常:

Exception in thread "main" java.lang.ClassCastException: b.B2 cannot be cast to a.A
    at a.Main.main(Main.java:22)

B2应该是一个A实例,任何想法为什么会这样?

1 个答案:

答案 0 :(得分:0)

您有两个名为a.A的类,一个由您的线程的默认类加载器加载,另一个由您的自定义类加载器加载。

这就是消息混乱的地方,因为你实际上有两个打印a.A的类,但是从不同的类加载器中你不能交换另一个。你需要做的是

Class classB2 = urlClassLoader.loadClass("b.B2")
Object ab2 = classB2.newInstance();

这是因为您的线程将加载的a.A来自默认的类加载器,即使它碰巧具有相同的名称,也不能使用它。

另一种方法是只有一个类加载器加载a.A

File f = new File("Z:\\Jars\\b.jar");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { f.toURL() });

这将使用ClassLoader.getSystemClassLoader()加载a.A,因此该名称只有一个类。