虽然我的类已加载,但Class.forName会抛出ClassNotFoundException

时间:2014-02-13 09:17:38

标签: java classloader urlclassloader

代码如下

它的作用是加载我放在主目录中的jar文件中的所有类。

import java.io.File;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import java.net.URLClassLoader;
import java.net.URL;
import java.util.Enumeration;
import java.lang.ClassLoader;
public class Plugin extends ClassLoader {
public static void main(String[] args) throws Exception {

    File file = new File(System.getProperty("user.home") + "/HelloWorld.jar");

    URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});

    JarFile jarFile = new JarFile(file);
    Enumeration<JarEntry> entries = jarFile.entries();

    while (entries.hasMoreElements()) {
        JarEntry element = entries.nextElement();
        if (element.getName().endsWith(".class")) {
            try {
                Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
                c.newInstance(); // this proves that class is loaded
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    Class cls = Class.forName("HelloWorld");
    cls.newInstance();
    Plugin p = new Plugin();
    p.checkIfLoaded();

}

public void checkIfLoaded() {
System.out.println("coming in");
if (findLoadedClass("HelloWorld") != null){
        System.out.println("Yepee, HelloWorld class is loaded !");
}
}

}

我的HelloWorld与https://github.com/HarishAtGitHub/doc/blob/master/makeExecutableJar/HelloWorld.java

中的相同

并使用上面提到的github帐户中的说明获取jar。

c.newInstance()有效。

我是如何确认的?

静态块被执行了......

Class.forName("HelloWorld")会抛出ClassNotFoundException

findLoadedClass("HelloWorld")为空..

我无法理解为什么会出现这种奇怪的行为?

请指导......

2 个答案:

答案 0 :(得分:2)

这是一个类加载器问题。

根据Javadocs to Class.forName,您正在使用当前类的类加载器查找类。作为您的主类,这将是JVM的引导类加载器(并且或多或少只包括标准库以及您作为-cp命令行参数提供的任何内容)。它不会委托给您实例化为局部变量的类加载器,因此不会返回 类加载器可以找到的类。

如果要明确指定类加载器,并调用

Class.forName("HelloWorld", true, clazzloader)

然后将搜索您刚刚创建的类加载器,并找到您的类。

答案 1 :(得分:1)

因为Class.forName(String)使用currentClassLoader并且您已在不同的ClassLoader中加载该类。

根据javadoc,调用Class.forName(String)等同于:

Class.forName(className, true, currentLoader)