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


当前回答

Java ClassNotFoundException vs NoClassDefFoundError

黑ClassLoader铝

静态与动态类加载

静态(隐式)类加载——引用、实例化或继承的结果。

MyClass myClass = new MyClass();

动态(显式)类加载是class . forname (), loadClass(), findSystemClass()的结果

MyClass myClass = (MyClass) Class.forName("MyClass").newInstance();

每个类都有一个ClassLoader,它使用loadClass(字符串名);这就是为什么

explicit class loader uses implicit class loader

NoClassDefFoundError是显式类装入器的一部分。Error是为了保证在编译期间出现这个类,但现在(在运行时)它不存在。

ClassNotFoundException是隐式类装入器的一部分。Exception对于可以额外使用的场景(例如反射)具有弹性。

其他回答

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

set classpath=%classpath%;axis.jar

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

set classpath=axis.jar;%classpath%;

这是迄今为止我找到的最好的解决办法。

假设我们有一个名为org的包。Mypackage包含的类:

HelloWorld(主类) SupportClass UtilClass

定义这个包的文件物理存储在目录D:\myprogram (Windows)或/home/user/myprogram (Linux)下。

文件结构如下所示:

当调用Java时,我们指定要运行的应用程序的名称:org.mypackage.HelloWorld。但是,我们还必须告诉Java在哪里查找定义包的文件和目录。所以要启动程序,我们必须使用下面的命令:

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

当我将另一个模块的Maven依赖添加到我的项目中时,我得到了这个错误,这个问题最终通过添加-Xss2m到我的程序的JVM选项来解决(自JDK5.0以来默认是1m字节)。人们认为程序没有足够的堆栈来加载类。

有一个有趣的例子,你可能会看到很多NoClassDefFoundErrors:

在类的静态块中抛出一个RuntimeException 拦截它(或者如果它在测试用例中抛出并不重要) 尝试创建该类的实例

static class Example {
    static {
        thisThrowsRuntimeException();
    }
}

static class OuterClazz {

    OuterClazz() {
        try {
            new Example();
        } catch (Throwable ignored) { //simulating catching RuntimeException from static block
            // DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
        }

        new Example(); //this throws NoClassDefFoundError
    }
}

NoClassDefError将伴随来自静态块RuntimeException的ExceptionInInitializerError一起抛出。


当你在UNIT TESTS中看到NoClassDefFoundErrors时,这一点尤其重要。

在某种程度上,您在测试之间“共享”静态块执行,但初始的ExceptionInInitializerError将仅在一个测试用例中。第一个使用有问题的Example类。其他使用Example类的测试用例只会抛出NoClassDefFoundErrors。