现有类的NoClassDefFoundError

时间:2012-11-22 03:34:43

标签: java noclassdeffounderror

我是一个经验丰富的程序员,我遇到了这个非常奇怪的问题,到目前为止我还没能解决。我收到了这个错误:

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发行版,只安装了最新的一个架构,问题仍然存在。 你们中的任何人以前见过这样的东西吗?

3 个答案:

答案 0 :(得分:2)

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

运行jar -tvf <jarname>。它应该将MiscIO类显示为“rec / MiscIO.class”。如果没有,则类加载器将无法找到它。

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


对于记录,冲突的Java版本不会导致这些确切症状出现问题。 (或者至少,&gt;&gt;我&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;


您的代码显示它更复杂,更模糊​​......可能与平台有关。

答案 1 :(得分:2)

另一个不太可能的解释可能是线程上下文ClassLoader

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

  

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

     

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

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

您可以执行的排除此操作的测试是声明应用程序的主线程中Class.forName("rec.MiscIO")不为空。

答案 2 :(得分:2)

老兄,你的文件柜有什么作用?

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

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