【问题标题】:Though my class was loaded, Class.forName throws ClassNotFoundException虽然我的课程已加载,但 Class.forName 会抛出 ClassNotFoundException
【发布时间】:2014-03-12 01:34:47
【问题描述】:

代码如下

它的作用是将所有类加载到我放置在我的主目录中的 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

jar 是使用上面提到的我的 github 帐户中的说明获得的。

c.newInstance() 有效。

我是如何确认的?

静态块被执行...

但是Class.forName("HelloWorld") 抛出ClassNotFoundException

还有findLoadedClass("HelloWorld") 为空..

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

请指导...

【问题讨论】:

  • HelloWorld 类在默认包中??
  • no .. 它与 META-INF 文件夹处于同一级别 ....

标签: java classloader urlclassloader


【解决方案1】:

这是一个类加载器问题。

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

如果您要明确指定类加载器,然后调用

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

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

【讨论】:

  • 你。如果我的课程已加载,那么无法从任何地方检查?我的 clazzLoader 应该总是被传递吗?加载的类信息是否保存在一个共同的地方?
  • 处理这种特殊情况的最简单方法是让您的类由引导(即主)类加载器加载。如果您将HelloWorld.jar 作为-cp 参数传递给Java 调用,则其中的类将由主类加载器自动加载,您无需执行任何其他操作。 (或者如果应用本身是一个 JAR,您可以设置其清单的 Class-Path 属性。)
  • 否则,如果您需要在运行时创建一个类加载器(无论出于何种原因),您可能希望将其设置为Thread's context classloader 以相对简单的方式传递它。不过,您可能仍然需要一些手动工作来从中获取类加载器,因为默认情况下,一个类自己的类加载器用于查找其他类。如果您想要任何其他行为,通常需要明确指定类加载器。
【解决方案2】:

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

根据javadoc,调用Class.forName(String)相当于:

Class.forName(className, true, currentLoader) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 2013-03-04
    • 2015-05-18
    相关资源
    最近更新 更多