尽管我的类已经加载,但 Class.forName 仍会抛出 ClassNotFoundException。

3

以下是代码:

它的作用是加载我放在家目录中的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")返回null...

我不明白为什么会出现这种奇怪的行为?

请指导...


2
HelloWorld类在默认包中吗? - Kick
它只是与META-INF文件夹处于同一级别。 - Harish Kayarohanam
2个回答

3

这是一个类加载器问题。

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

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

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

然后,刚刚创建的类加载器将被搜索,您的类应该会被找到。


那么,无法从任何地方检查我的类是否已加载?我的clazzLoader应该始终传递吗?加载的类信息是否保存在公共位置? - Harish Kayarohanam
处理这种特殊情况最简单的方法是让你的类由引导(即主)类加载器加载。如果你将 HelloWorld.jar 作为 -cp 参数传递给你的 Java 调用,其中的类将自动由主类加载器加载,你不需要做任何其他事情。(或者如果应用本身是一个 JAR 文件,你可以设置其清单文件的 Class-Path 属性。) - Andrzej Doyle
否则,如果您需要在运行时创建一个类加载器(无论出于什么原因),您可能希望将其设置为线程的上下文类加载器,以相对容易地传递它。 但是,您可能仍然需要一些手动工作来从中获取类加载器,因为默认情况下,一个类的自身类加载器用于查找其他类。 如果您想要任何其他行为,则通常需要显式指定类加载器。 - Andrzej Doyle

2

由于Class.forName(String)使用当前ClassLoader,而您在不同的ClassLoader中加载了类。

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

Class.forName(className, true, currentLoader) 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接