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


当前回答

对此,我的解决方案是为缺失的特定类“利用”类路径内容。在我的情况下,我有2个依赖项,虽然我能够成功地编译使用javac…,我不能运行产生的类文件使用java…,因为BouncyCastle jar中的Dynamic类不能在运行时加载。

javac --classpath "ext/commons-io-2.11.0;ext/bc-fips-1.0.2.3" hello.java

因此在编译时和运行时,JVM知道在哪里获取Apache Commons和BouncyCastle依赖项,然而,当运行这个时,我得到了

Error: Unable to initialize main class hello
Caused by: java.lang.NoClassDefFoundError: 
org/bouncycastle/jcajce/provider/BouncyCastleFipsProvider

因此,根据类路径,我在相同的位置手动创建了一个名为ext的新文件夹,然后在其中放置了BouncyCastle jar,以确保在运行时可以找到它。只要结果清单中指定了jar的位置,您就可以将jar相对于类文件或jar文件放置。注意,我只需要利用包含丢失类文件的一个jar。

其他回答

当我试图在Tomcat/JBOSS服务器上部署应用程序时,我得到了NoClassDefFoundError。我尝试了不同的依赖关系来解决这个问题,但总是得到相同的错误。标记所有javax。*依赖提供在pom.xml,和战争字面上没有依赖。但这个问题还是不断出现。

最终意识到src/main/webapps/WEB-INF/classes有类文件夹被复制到我的战争,所以不是编译类,这个类被复制,因此没有依赖改变解决问题。

因此要小心,如果任何以前编译的数据被复制,删除类文件夹和新的编译后,它工作!..

当运行时类装入器装入的类不能访问已经由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;
            }
        });
    }
}

下面是演示java.lang.NoClassDefFoundError的代码。具体的解释请看Jared的回答。

NoClassDefFoundErrorDemo.java

public class NoClassDefFoundErrorDemo {
    public static void main(String[] args) {
        try {
            // The following line would throw ExceptionInInitializerError
            SimpleCalculator calculator1 = new SimpleCalculator();
        } catch (Throwable t) {
            System.out.println(t);
        }
        // The following line would cause NoClassDefFoundError
        SimpleCalculator calculator2 = new SimpleCalculator();
    }

}

SimpleCalculator.java

public class SimpleCalculator {
    static int undefined = 1 / 0;
}

此错误可能是由未检查的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

我在项目中使用Spring Framework和Maven解决了这个错误。

类中存在运行时错误。我将一个属性读取为整数,但是当它从属性文件读取值时,它的值是double。

Spring没有提供运行时在哪一行上失败的完整堆栈跟踪。 它只是说NoClassDefFoundError。但是当我作为一个原生Java应用程序执行它时(将它从MVC中取出),它给出了ExceptionInInitializerError,这是真正的原因,也是我跟踪错误的方式。

@xli的回答让我洞察到我的代码中可能存在的错误。