代码之家  ›  专栏  ›  技术社区  ›  Henrik Paul

动态类加载在运行时失败

  •  3
  • Henrik Paul  · 技术社区  · 16 年前

    我有下面的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();
    

    这汇编得很好。但当我试图运行它时,会发生一些奇怪的事情;a 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 回复  |  直到 16 年前
        1
  •  4
  •   Brett Kail    16 年前

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

    不使用反射就做你想做的事情是不方便的。您需要(1)创建一个单独的类来直接访问junitcore,(2)在urlcllassloader(directory或jar)上包含该类的路径,(3)使用反射加载该类,以及(4)使用反射调用该类上的方法。

        2
  •  -1
  •   Affe    16 年前

    你也不需要这样做吗 .loadClass("org.junit.runner.JUnitCore", **true**); 或者在创建新实例之前调用类对象的resolveclass()?