【问题标题】:NoClassDefFoundError on existing class现有类上的 NoClassDefFoundError
【发布时间】:2012-11-10 10:16:25
【问题描述】:

我是一个经验丰富的程序设计人员,我遇到了一个非常奇怪的问题,到目前为止我还无法解决。我收到此错误:

Exception in thread "Thread-0" java.lang.NoClassDefFoundError: rec/MiscIO
        at rec.RECTool.run(RECTool.java:264)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: rec.MiscIO
        at java.net.URLClassLoaderrun(Unknown Source)
        at java.net.URLClassLoaderrun(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 2 more

这是相关的行:

File savedTo = MiscIO.copyJar(root);

我不明白的是,这是一个小应用程序,并且使用的类在同一个包中。除了类名和内容外,基本相同。但是,我只在我的一些课程中特别得到了错误,而不是全部。我在错误发生之前使用这些行,它们在同一个包中。

Logger.log("Found new root: " + newRoots[i0]);
...
FileLocker locker = new FileLocker();
...
locker.lock(PathManager.getJar());

所以三个类的设置与出错的一个基本相同,只有一个抛出异常。这对我来说毫无意义。

我尝试了各种参数来运行 jar,包括修改类路径和直接调用主类而不是使用 jar 命令,但无济于事,例如:

java -jar <jarname>
java -cp . <jarname>
java -cp <jarname> -jar <jarname>
java -cp <jarname> <main class here>

但是,如果我解压缩 jar 并运行程序,则不会发生错误。我认为这可能是 MiscIO 无法加载或静态初始化程序无法加载的某种依赖关系,但我的代码中都没有。

另外,我正在使用 Netbeans 生成 jar,并且清单设置正确。这是完整的代码:

    package rec;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URL;

/**
 * @author Colby
 */
public class MiscIO {

    public static void copyJar(RandomAccessFile out) throws IOException {
        URL jarSource = RECTool.class.getProtectionDomain().getCodeSource().getLocation();

        InputStream in = null;
        try {
            in = jarSource.openStream();
            copyToRAF(in, out);

        } finally {
            if (in != null) {
                in.close();
            }
        }
    }

    public static File copyJar(File saveJarTo) throws IOException {
        URL jarSource = RECTool.class.getProtectionDomain().getCodeSource().getLocation();
        saveJarTo = new File(saveJarTo, "classlist.jar");

        InputStream in = null;
        OutputStream out = null;
        try {
            in = jarSource.openStream();
            out = new FileOutputStream(saveJarTo);
            copyStream(in, out);

        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
        return saveJarTo;
    }

    public static void copyStream(InputStream in, OutputStream out) throws IOException {
        int len;
        byte[] data = new byte[1024 * 8];
        while ((len = in.read(data)) != -1) {
            out.write(data, 0, len);
        }
        out.flush();
    }

    public static void copyToRAF(InputStream in, RandomAccessFile raf) throws IOException {
        raf.seek(0L);

        int len;
        byte[] data = new byte[1024 * 8];
        while ((len = in.read(data)) != -1) {
            raf.write(data, 0, len);
        }
    }

    public static void copyFile(File from, File to) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream(from);
            out = new FileOutputStream(to);
            copyStream(in, out);

        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

最后一点,我认为这可能是我的机器上安装的 Java 版本冲突,或者偶然发生的 x86/x64 冲突,所以我卸载了所有 Java 发行版,只安装了一个架构中的最新版本,问题仍然存在。 你们有谁以前见过这样的事情吗?

【问题讨论】:

  • NoClassDefFoundError:如果 Java 虚拟机或 ClassLoader 实例尝试加载类的定义(作为正常方法调用的一部分或使用新表达式)并且无法构造该类的有效表示。
  • 报错说明问题出在RECTool.java:264。贴出相应的 RECTool.java 代码,看看你是如何调用 MiscIO 类的。
  • (也就是说异常并不意味着找不到类。事实上,类很可能被找到了,但是有些东西阻止了它被使用,通常是JAR文件不匹配,但偶尔会在静态初始化期间出现错误或类似情况。通常在异常跟踪中会有一个较早的异常提示特定原因。)
  • 这有点像类加载器问题,您在不同的类加载器下加载了相同的类。
  • (虽然考虑到斯蒂芬的回答,但很可能您只是将类放在 jar 中的错误位置——不是在目录“rec”中,而是在根目录中。)

标签: java noclassdeffounderror


【解决方案1】:

根据您所说,最可能的解释是您错误地创建了 JAR 文件。

运行jar -tvf &lt;jarname&gt;。它应该将 MiscIO 类显示为“rec/MiscIO.class”。如果没有,那么类加载器将无法找到它。

(还有其他不太可能的解释;例如,涉及自定义类加载器和/或 JVM 试图加载之前类加载失败的类。)


郑重声明,冲突的 Java 版本不会导致出现这些确切症状的问题。 (或者至少,>>我


您的代码表明它是更复杂和晦涩的东西......并且可能依赖于平台。

【讨论】:

  • 这是一个很好的观点 - 导致此错误的一个可能原因是类在 jar 中的错误位置,或者相反,类中没有正确的包规范。
  • @HotLicks - 是的。请记住,代码确实编译,并且当他解压缩 JAR 时它确实运行。 (当然,他没有说怎么……)
  • 是的,如果它在 JAR 解包的情况下运行,那么将类放在 JAR 中错误位置的可能性很高(尽管以其他方式搞砸类路径也相当高名单上)。
  • 我运行了该命令,令人惊讶的是它是正确的:2724 Wed Nov 21 21:23:34 CST 2012 rec/MiscIO.class
【解决方案2】:

老兄,你的文件柜是做什么用的?

1    FileLocker locker = new FileLocker();
2    locker.lock(PathManager.getJar());
3    File savedTo = MiscIO.copyJar(root);

如果第[2]行独占锁定包含MiscIO.class的jar,第[3]行无法加载MiscIO类。

【讨论】:

  • 哦!这绝对是问题所在。我认为整个 jar(和依赖项)是在进程启动时加载的。可能不会。谢谢老兄,永远不会发现!
  • JAR 被打开并在类加载器第一次引用它时读取目录,但各个类在加载时从 JAR 文件中获取。
【解决方案3】:

另一个不太可能的解释,可能是Thread Context ClassLoader

我看到 Exception 发生在一个新的 Thread 中,所以可能是 Context Class Loader 和调用 Thread 不一样。这取决于创建新线程的代码,以及它是否位于找不到类的相同类路径中,如以下 Stack Overflow 答案中所述:

每个类都将使用它自己的类加载器来加载其他类。因此,如果 ClassA.class 引用 ClassB.class 那么 ClassB 需要在 ClassA 的类加载器的类路径,或者它的父类。

线程上下文类加载器是当前的类加载器 当前线程。可以从 ClassLoaderC 中的类创建对象 然后传递给 ClassLoaderD 拥有的线程。在这种情况下 对象需要使用 Thread.currentThread().getContextClassLoader() 如果它想加载其上不可用的资源,则直接 自己的类加载器。

(摘自: Difference between thread's context class loader and normal classloader)

您可以做一个测试来排除这种情况,即断言Class.forName("rec.MiscIO") 在您的应用程序的主线程中不为空。

【讨论】:

    猜你喜欢
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    相关资源
    最近更新 更多