为什么在Java中收到NoClassDefFoundError?

Why am I getting a NoClassDefFoundError in Java?

运行Java应用程序时得到NoClassDefFoundError。 通常是什么原因造成的?


尽管这可能是由于编译时和运行时之间的类路径不匹配导致的,但不一定是正确的。

在这种情况下,请务必牢记两个或三个不同的异常:

  • java.lang.ClassNotFoundException此异常表明在类路径上找不到该类。这表明我们正在尝试加载类定义,并且该类在类路径中不存在。

  • java.lang.NoClassDefFoundError此异常表明JVM在其内部类定义数据结构中查找了类的定义,但未找到。这与说无法从类路径中加载不同。通常,这表明我们以前曾尝试从类路径中加载类,但由于某种原因而失败-现在我们正尝试再次使用该类(由于上次失败,因此需要对其进行加载),但是我们甚至不打算尝试加载它,因为我们无法更早加载它(并且合理地怀疑我们会再次失败)。较早的故障可能是ClassNotFoundException或ExceptionInInitializerError(指示静态初始化块中的故障)或许多其他问题。关键是,NoClassDefFoundError不一定是类路径问题。


  • 当您的代码依赖于一个类文件,并且该类文件在编译时存在但在运行时未找到时,会导致这种情况。在构建时间和运行时类路径中寻找差异。


    这是说明java.lang.NoClassDefFoundError的代码。请参阅Jared的答案以获取详细说明。

    NoClassDefFoundErrorDemo.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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

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

    Java中的NoClassDefFoundError

    定义:

  • Java虚拟机无法在运行时找到编译时可用的特定类。

  • 如果一个类在编译期间存在,但在运行时在java classpath中不可用。

  • enter image description here

    例子:

  • 该类不在Classpath中,没有确定的了解方法,但是很多时候您只需要看一下即可打印System.getproperty(" java.classpath"),它将从那里打印出类路径,您至少可以得到您的实际运行时类路径的想法。
  • NoClassDefFoundError的一个简单示例是类属于丢失的JAR文件,或者未将JAR添加到类路径中,或者有时有人更改了jar的名称,例如我的同事之一将tibco.jar更改为tibco_v3.jar,程序是java.lang.NoClassDefFoundError失败,我想知道怎么了。

  • 只需尝试在您认为可以使用的类路径上显式地使用-classpath选项即可运行,如果可以正常运行,那么这肯定是有人重写Java类路径的简短标志。

  • JAR文件的权限问题也可能导致Java中出现NoClassDefFoundError。
  • XML配置上的错字也可能导致Java中的NoClassDefFoundError。
  • 当在包中定义的已编译类在加载时不在同一个包中时(如JApplet),它将在Java中引发NoClassDefFoundError。
  • 可能的解决方案:

  • 该类在Java Classpath中不可用。
  • 如果您在J2EE环境中工作,则多个Classloader之间Class的可见性也可能导致java.lang.NoClassDefFoundError,请参阅示例和场景一节以获取详细讨论。
  • 在日志文件中检查java.lang.ExceptionInInitializerError。由于静态初始化失败而导致的NoClassDefFoundError非常普遍。
  • 由于NoClassDefFoundError是java.lang.LinkageError的子类,因此如果其中一个依赖项(如本机库)可能不可用,它也可能会出现。
  • 任何启动脚本都将覆盖Classpath环境变量。
  • 您可能正在使用jar命令运行程序,并且清单文件的ClassPath属性中未定义类。
  • 资源:

    解决NoClassDefFoundError的3种方法

    java.lang.NoClassDefFoundError问题模式


    我发现有时使用在运行时发现的类的不兼容版本编译代码时,有时会出现NoClassDefFound错误。我记得的特定实例与apache轴库有关。我的运行时类路径上实际上有2个版本,并且它选择的是过时且不兼容的版本,而不是正确的版本,从而导致NoClassDefFound错误。这是在命令行应用程序中,我在其中使用与此类似的命令。

    1
    set classpath=%classpath%;axis.jar

    我能够使用以下命令获取正确的版本:

    1
    set classpath=axis.jar;%classpath%;

    这是我到目前为止发现的最佳解决方案。

    假设我们有一个名为org.mypackage的包,其中包含以下类:

    • HelloWorld(主类)
    • SupportClass
    • UtilClass

    并且定义此软件包的文件实际存储在目录D:\myprogram(在Windows上)或/home/user/myprogram(在Linux上)下。

    文件结构将如下所示:
    enter image description here

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


    我在Maven中使用Spring Framework,并在我的项目中解决了此错误。

    该类中存在运行时错误。我正在将属性读取为整数,但是当它从属性文件读取值时,其值是两倍。

    Spring并没有给我完整的堆栈跟踪信息,表明运行失败的那一行。
    它只是说NoClassDefFoundError。但是,当我将其作为本机Java应用程序(从MVC中取出)执行时,它给出了ExceptionInInitializerError的真正原因,这也是我跟踪错误的方式。

    @xli的答案使我深入了解了我的代码中可能存在的问题。


    当运行时类加载器加载的类无法访问Java rootloader已加载的类时,出现NoClassFoundError。由于不同的类加载器位于不同的安全域中(根据Java),因此jvm不允许在运行时加载器地址空间中解析由根加载器加载的类。

    使用" java -javaagent:tracer.jar [您的Java插件]"运行程序

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    // 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;
                }
            });
        }
    }

    尤其是如果您在UNIT TESTS中看到NoClassDefFoundErrors,请仔细阅读...

    您可能会看到很多NoClassDefFoundErrors的有趣情况是:

  • Examplestatic块中的throwRuntimeException
  • 拦截它(或者就像在测试用例中抛出一样没关系)
  • 尝试创建此类Example的实例
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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将与ExceptionInInitializerError一起从静态块RuntimeException中引发。

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

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


    如果您已生成代码(EMF等),则可能有太多静态初始化程序占用所有堆栈空间。

    请参见堆栈;溢出问题;如何增加Java堆栈大小?


    以下技术对我有很多帮助:

    1
    System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

    其中,TheNoDefFoundClass是由于对程序使用的同一个库的较旧版本的偏好而可能"丢失"的类。这种情况最常发生在以下情况中:将客户端软件部署到一个占主导地位的容器中,并带有其自己的类加载器和成千上万个最流行的lib的古代版本。


    我通过禁用所有模块的preDexLibraries解决了我的问题:

    1
    2
    3
    dexOptions {
            preDexLibraries false
            ...

    当静态初始化程序尝试加载运行时不可用的资源束时,例如也会出现NoClassDefFoundError,受影响的类尝试从META-INF目录加载但不存在的属性文件。如果您没有捕获NoClassDefFoundError,有时您将看不到完整的堆栈跟踪信息。为了克服这个问题,您可以为Throwable临时使用catch子句:

    1
    2
    3
    4
    5
    try {
        // Statement(s) that cause the affected class to be loaded
    } catch (Throwable t) {
        Logger.getLogger(";lt;logger-name;gt;").info("Loading my class went wrong", t);
    }

    也可能是因为您从IDE复制具有特定程序包名称的代码文件,并想尝试使用终端运行它。您必须首先从代码中删除程序包名称。
    这发生在我身上。


    如果有人是因为java.lang.NoClassDefFoundError: org/apache/log4j/Logger错误而来这里的,那么在我的情况下,它是由于我使用log4j 2而产生的(但是我没有添加它随附的所有文件),而某些依赖库使用了log4j 1。添加Log4j 1.x桥:log4j 2随附的jar log4j-1.2-api-;lt;version;gt;.jar。有关log4j 2迁移的更多信息。


    同一项目的两个不同的结帐副本

    就我而言,问题是Eclipse无法区分同一项目的两个不同副本。我有一个锁定在主干(SVN版本控制)上,而另一个则一次在一个分支中工作。我尝试将工作副本中的一个更改作为JUnit测试用例进行了测试,其中包括将一个私有内部类单独提取为一个公共类,并且在工作时,我打开了该项目的另一个副本以查看其他内容。需要更改的部分代码。在某个时候,NoClassDefFoundError突然弹出,抱怨私有内部类不存在。双击堆栈跟踪将我带到错误的项目副本中的源文件。

    关闭项目的主干副本并再次运行测试用例解决了这个问题。


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

    就我而言,通过使用SDKMAN!从Java 9切换到Java 8,在构建备受瞩目的开源项目时,我能够解决此错误。

    1
    2
    3
    sdk list java
    sdk install java 8u152-zulu
    sdk use java 8u152-zulu

    然后按照以下说明进行全新安装。

    当使用Maven作为构建工具时,有时会很有帮助-通常令人欣喜的是,在禁用测试的情况下进行全新的"安装"构建。

    1
    mvn clean install -DskipTests

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

    1
    mvn test

    当我没有在项目的Java Build Path的" Order and Export"选项卡上导出类时,出现NoClassDefFound错误。确保在添加到项目的构建路径中的所有依赖项的"订单和导出"选项卡中打上对勾。请参阅Eclipse警告:XXXXXXXXXXX.jar将不会导出或发布。运行时ClassNotFoundExceptions可能会导致。


    Java无法在运行时中找到类A。
    A类在其他工作区的Maven项目ArtClient中。
    因此,我将ArtClient导入了我的Eclipse项目。
    我的两个项目使用ArtClient作为依赖项。
    我将库参考更改为这些项目的项目参考(构建路径->配置构建路径)。

    问题消失了。


    我遇到了同样的问题,而且库存很多小时。

    我找到了解决方案。在我的情况下,因此定义了静态方法。 JVM无法创建该类的另一个对象。

    例如,

    1
    private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort),"http");

    从SRC库中删除了两个文件后,我收到了此消息,当我将它们放回时,我一直看到此错误消息。

    我的解决方案是:重新启动Eclipse。从那时起,我再也没有看到此消息:-)


    确保在module:appmodule:lib中匹配:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    android {
        compileSdkVersion 23
        buildToolsVersion '22.0.1'
        packagingOptions {
        }

        defaultConfig {
            minSdkVersion 17
            targetSdkVersion 23
            versionCode 11
            versionName"2.1"
        }


    推荐阅读