当我运行Java应用程序时,我得到了一个NoClassDefFoundError。造成这种情况的典型原因是什么?


当前回答

我从SRC库中删除了两个文件后得到了这个消息,当我把它们带回来时,我一直看到这个错误消息。

我的解决方案是:重新启动Eclipse。从那以后我就再没见过这条消息了:-)

其他回答

此错误可能是由未检查的Java版本要求引起的。

在我的案例中,当我构建一个备受瞩目的开源项目时,通过使用SDKMAN从Java 9切换到Java 8,我能够解决这个错误。

sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu

然后按照下面的描述进行干净安装。


在使用Maven作为构建工具时,在禁用测试的情况下进行干净的“安装”构建有时是有帮助的,而且通常是令人满意的。

mvn clean install -DskipTests

现在已经构建并安装了所有内容,您可以继续运行测试。

mvn test

当运行时类装入器装入的类不能访问已经由java rootloader装入的类时,我得到NoClassFoundError。因为不同的类装入器在不同的安全域中(根据java), jvm不允许已经由rootloader装入的类在运行时装入器地址空间中被解析。

使用'java -javaagent:trace .jar[你的java ARGS]'运行程序

它产生显示已加载类的输出,以及加载该类的加载器env。追踪类为什么不能解析是非常有用的。

// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5

import java.lang.instrument.*;
import java.security.*;

// manifest.mf
// Premain-Class: ClassLoadTracer

// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class

// java -javaagent:tracer.jar  [...]

public class ClassLoadTracer 
{
    public static void premain(String agentArgs, Instrumentation inst) 
    {
        final java.io.PrintStream out = System.out;
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

                String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
                out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);

                // dump stack trace of the thread loading class 
                Thread.dumpStack();

                // we just want the original .class bytes to be loaded!
                // we are not instrumenting it...
                return null;
            }
        });
    }
}

我发现,当使用运行时发现的不兼容的类版本编译代码时,有时会得到NoClassDefFound错误。我记得的具体实例是apache axis库。在我的运行时类路径上实际上有2个版本,它正在挑选过时和不兼容的版本,而不是正确的版本,导致NoClassDefFound错误。这是在一个命令行应用程序中,我正在使用类似的命令。

set classpath=%classpath%;axis.jar

我能够让它拿起正确的版本使用:

set classpath=axis.jar;%classpath%;

在我的情况下,由于JDK版本不匹配,我得到了这个错误。当我试图从Intelij运行应用程序时,它不工作,但从命令行运行它就工作了。这是因为Intelij试图用Java 11 JDK运行它,但在命令行上,它是用Java 8 JDK运行的。在文件>项目结构>项目设置>项目SDK下切换设置后,它为我工作了。

当静态初始化器试图加载一个在运行时不可用的资源包时,也会发生NoClassDefFoundError,例如受影响的类试图从META-INF目录加载一个属性文件,但不存在。如果你没有捕获NoClassDefFoundError,有时你将无法看到完整的堆栈跟踪;为了克服这个问题,你可以临时为Throwable使用一个catch子句:

try {
    // Statement(s) that cause(s) the affected class to be loaded
} catch (Throwable t) {
    Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}