动态类加载在运行时失败

时间:2010-05-21 22:57:27

标签: java exception dynamic classloader

我有以下Java代码片段:

final Class<?> junitCoreClass = AccessController.doPrivileged(
    new PrivilegedAction<URLClassLoader>() {
      @Override
      public URLClassLoader run() {
        return new URLClassLoader(new URL[] { junitJarUrl });
      }
    }).loadClass("org.junit.runner.JUnitCore");

System.out.println(junitCoreClass.getName());
final JUnitCore junitCore = (JUnitCore) junitCoreClass.newInstance();

编译好。但是当我试图运行它时,会发生一些奇怪的事情;最后一行抛出java.lang.NoClassDefFoundError,引用刚刚加载的类。奇怪的是,println打印出确切的类名。

我检查过如果我将新实例引用保留为Object并仅通过反射操作它,一切都很好,所以违规代码必须是显式转换。

有人可以向我解释为什么会发生这种情况,并告诉我如何实现我想要做的事情?

PS:对于那些想要查看更接近堆栈跟踪的人来说,没有太多要显示的内容:

java.lang.NoClassDefFoundError: org/junit/runner/JUnitCore
  at [last line of example)
  [lines from my app]
Caused by: java.lang.ClassNotFoundException: org.junit.runner.JUnitCore
  at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:315)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:330)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:250)
  at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:398)
  at [last line of example]
  [lines from my app]

2 个答案:

答案 0 :(得分:4)

问题是你的主类是由类路径上没有JUnit的系统类加载器(包含-classpath的加载器)加载的。然后,您创建一个单独的类加载器,在类路径上只有JUnit。当您的主类尝试强制转换为JUnitCore时,系统类加载器会被要求加载它不包含的JUnitCore,因此会发生NoClassDefFoundError。

如果不使用反射,就没有方便的方法来做你想做的事情。您需要(1)创建一个直接访问JUnitCore的单独类,(2)在URLClassLoader(目录或JAR)上包含该类的路径,(3)使用反射来加载该类,以及(4)使用反射来在该类上调用一个方法。

答案 1 :(得分:-1)

您是否需要执行.loadClass("org.junit.runner.JUnitCore", **true**);或者在创建新实例之前在类对象上调用resolveClass()?