最近我创建了一些必须动态加载/卸载外部jar包的东西。我现在尝试使用URLClassLoader
执行此操作,但在尝试创建新实例时,我一直收到NoClassDefFoundError
。
由于构造函数中的代码已执行,似乎外部类已成功加载,但ClassNotFoundException
和NoClassDefFoundError
仍然被抛出。
我制作了一个重新创建错误的小包,下面是代码:
以下代码位于ExternalObject.class
,该文件放在.jar文件中,我试图动态加载:
package test.outside;
import test.inside.InternalObject;
public class ExternalObject
{
private final String str;
public ExternalObject()
{
this.str = "Creating an ExternalObject with nothing.";
this.print();
}
public ExternalObject(InternalObject inObj)
{
this.str = inObj.getString();
this.print();
}
public void print()
{
System.out.println(this.str);
}
}
以下代码位于InternalObject.class
:
package test.inside;
public class InternalObject
{
private final String str;
public InternalObject(String s)
{
this.str = s;
}
public String getString()
{
return this.str;
}
}
我使用下面的Main.class
测试了该文件:
package test.inside;
import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import test.outside.ExternalObject;
public class Main
{
public static void main(String[] args)
{
try
{
File externalJar = new File("F:\\Dev\\ext.jar");
URLClassLoader uclTest = new URLClassLoader(new URL[]{externalJar.toURI().toURL()});
Class<?> clazz = uclTest.loadClass("test.outside.ExternalObject");
InternalObject inObj = new InternalObject("Creating an ExternalObject with an InternalObject.");
try
{
System.out.println("Test 1: Attempt to create an instance of the ExternalObject.class with an InternalObject in the constructor.");
Constructor<?> conTest = clazz.getConstructor(InternalObject.class);
ExternalObject extObj = (ExternalObject)conTest.newInstance(inObj);
}
catch(Throwable t)
{
System.out.println("Test 1 has failed. :(");
t.printStackTrace();
}
System.out.println();
try
{
System.out.println("Test 2: Attempt to create an instance of the ExternalObject.class with a void constructor.");
Constructor<?> conTest = clazz.getConstructor();
ExternalObject extObj = (ExternalObject)conTest.newInstance();
}
catch(Throwable t)
{
System.out.println("Test 2 has failed. :(");
t.printStackTrace();
}
uclTest.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
InternalObject.class
和Main.class
都在一个jar包中,它在启动时包含在类路径中。
我在控制台中得到了这个:
Console output screenshot
当执行this.print()
的两个构造函数中的代码ExternalObject.class
时,我真的不知道错误是什么。救命! :(
更新:谢谢你!但我实际上想要创建ExternalObject
的实例以供进一步使用,例如从其他类访问其中的方法。有什么办法可以将创建的实例作为ExternalObject
返回吗?或者我必须使用getMethod()
和invoke()
来访问这些方法?
此致 泽文
答案 0 :(得分:1)
我认为因为涉及两个classLoaders,并且您尝试将一个对象从classLoader转换为另一个类加载器中的对象。但这只是猜测。
答案 1 :(得分:1)
您的Main
类引用ExternalObject
,因此已编译的Main.class
依赖于ExternalObject
。
现在,当您运行Main
并且ExternalObject
仅在ext.jar
中可用但在用于运行Main
的类路径中不可用时,会发生以下情况:
uclTest
类加载器从ExternalObject
成功加载ext.jar
。创建也成功(由构造函数中的print语句看到)。
但失败的是对局部变量ExternalObject extObj
的分配。
Main
无法使用加载的类ExternalObject
,因为它由不同的类加载器加载。 ExternalObject
的类路径中也没有Main
,您将获得NoClassDefFoundError
。
删除两个作业ExternalObject extObj = (ExternalObject)
时,您的测试应该没有问题。
答案 2 :(得分:0)
如何运行Main类导致问题。
正如你所说,我创建了名为 ext1.jar 的jar,其中包含ExternalObject和InternalObjct类文件。 并使用Main和InternalObject类文件创建 ext.jar 。
如果我运行以下命令,它会抛出异常,就像你提到的那样
java -classpath。; C: \ path \ to \ ext.jar test.inside.Main
但是,如果我运行以下命令,它运行正常,没有任何异常
java -classpath。; C: \路径\到\ ext1.jar; C: \ path \ to \ ext.jar test.inside.Main
答案 3 :(得分:0)
万岁!!我刚刚为我的代码找到了更好的方法!我所做的是使用我需要的所有抽象方法创建abstract
类ExternalBase.class
,然后从ExternalObject.class
继承ExternalBase.class
。因此,动态加载的类既不必加载到自定义加载器中,也不必由使用该对象的类导入,并且代码对我来说非常完美。 :)