使用 URLClassLoader 加载 class 时不断出现 NoClassDefFoundError
Keep getting NoClassDefFoundError while loading a class with URLClassLoader
最近我正在创建一些必须动态地 load/unload 外部 jar 包的东西。我现在正尝试使用 URLClassLoader
执行此操作,但在尝试创建新实例时我不断收到 NoClassDefFoundError
。
似乎外部class加载成功,因为构造函数中的代码被执行了,但是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 包中,启动时包含在 class 路径中。
我在控制台中得到了这个:
Console output screenshot
由于 ExternalObject.class
的两个构造函数中的代码 this.print()
都被执行了,我真的不知道出了什么问题。帮助! :(
更新:谢谢你!!!但我实际上想创建一个 ExternalObject
的实例以供进一步使用,例如从其他 classes 访问其中的方法。有什么方法可以 return 创建的实例作为 ExternalObject
吗?或者我必须使用 getMethod()
和 invoke()
来访问这些方法?
真诚的,
泽文
我认为是因为涉及两个 classLoader,并且您尝试将一个对象从一个 classLoader 转换为另一个 class 加载器的对象。但只是猜测。
您的 Main
class 引用 ExternalObject
因此编译的 Main.class
依赖于 ExternalObject
.
现在,当您 运行 Main
和 ExternalObject
仅在 ext.jar
中可用但在用于 运行 的 class 路径中不可用时Main
发生以下情况:
uclTest
class 加载程序成功从 ext.jar
加载 ExternalObject
。同样创建成功(通过构造函数中的打印语句看到)。
但是失败的是对局部变量的赋值ExternalObject extObj
。
Main
无法使用已加载的 class ExternalObject
,因为它是由不同的 class 加载程序加载的。 Main
的 class 路径中也没有 ExternalObject
,你得到一个 NoClassDefFoundError
.
当您删除两个作业 ExternalObject extObj = (ExternalObject)
。
时,您的测试应该 运行 没有问题
你是如何运行宁主要 class 导致问题。
如您所说,我创建了名为 ext1.jar 的 jar,其中包含 ExternalObject 和 InternalObjct class 文件。
并使用 Main 和 InternalObject class 文件创建了 ext.jar。
如果我运行下面的命令,它会抛出你提到的异常
java -classpath .;C:
\path\to\ext.jar test.inside.Main
但是,如果我 运行 以下命令,它 运行 没问题,没有任何异常
java -classpath .;C:
\path\to\ext1.jar;C:
\path\to\ext.jar test.inside.Main
万岁!!我刚刚为我的代码找到了更好的方法!我所做的是用我需要的所有抽象方法创建一个 abstract
class ExternalBase.class
,然后从 ExternalBase.class
继承 ExternalObject.class
。因此,动态加载的 class 既不必加载到自定义加载器中,也不必由使用该对象的 classes 导入,代码对我来说非常完美。 :)
最近我正在创建一些必须动态地 load/unload 外部 jar 包的东西。我现在正尝试使用 URLClassLoader
执行此操作,但在尝试创建新实例时我不断收到 NoClassDefFoundError
。
似乎外部class加载成功,因为构造函数中的代码被执行了,但是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 包中,启动时包含在 class 路径中。
我在控制台中得到了这个:
Console output screenshot
由于 ExternalObject.class
的两个构造函数中的代码 this.print()
都被执行了,我真的不知道出了什么问题。帮助! :(
更新:谢谢你!!!但我实际上想创建一个 ExternalObject
的实例以供进一步使用,例如从其他 classes 访问其中的方法。有什么方法可以 return 创建的实例作为 ExternalObject
吗?或者我必须使用 getMethod()
和 invoke()
来访问这些方法?
真诚的, 泽文
我认为是因为涉及两个 classLoader,并且您尝试将一个对象从一个 classLoader 转换为另一个 class 加载器的对象。但只是猜测。
您的 Main
class 引用 ExternalObject
因此编译的 Main.class
依赖于 ExternalObject
.
现在,当您 运行 Main
和 ExternalObject
仅在 ext.jar
中可用但在用于 运行 的 class 路径中不可用时Main
发生以下情况:
uclTest
class 加载程序成功从 ext.jar
加载 ExternalObject
。同样创建成功(通过构造函数中的打印语句看到)。
但是失败的是对局部变量的赋值ExternalObject extObj
。
Main
无法使用已加载的 class ExternalObject
,因为它是由不同的 class 加载程序加载的。 Main
的 class 路径中也没有 ExternalObject
,你得到一个 NoClassDefFoundError
.
当您删除两个作业 ExternalObject extObj = (ExternalObject)
。
你是如何运行宁主要 class 导致问题。
如您所说,我创建了名为 ext1.jar 的 jar,其中包含 ExternalObject 和 InternalObjct class 文件。 并使用 Main 和 InternalObject class 文件创建了 ext.jar。
如果我运行下面的命令,它会抛出你提到的异常
java -classpath .;C: \path\to\ext.jar test.inside.Main
但是,如果我 运行 以下命令,它 运行 没问题,没有任何异常
java -classpath .;C: \path\to\ext1.jar;C: \path\to\ext.jar test.inside.Main
万岁!!我刚刚为我的代码找到了更好的方法!我所做的是用我需要的所有抽象方法创建一个 abstract
class ExternalBase.class
,然后从 ExternalBase.class
继承 ExternalObject.class
。因此,动态加载的 class 既不必加载到自定义加载器中,也不必由使用该对象的 classes 导入,代码对我来说非常完美。 :)