为什么我会在Java中收到NoClassDefFoundError?


529

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


1
我相信,如果不使用正确的语法运行Java程序,也会发生这种情况。例如,您必须从root bin文件夹中使用完整的包名称(即my.package.myClass)来调用您的类。如果可以的话,我会更具体一些,但我不是一个Java专家。我只记得把它弄乱了几次。
坦率的哈德

17
@BoltClock我们需要一个规范的问题来指出众多重复项。为什么不能呢?
2014年

21
您是否考虑过更改已接受的答案,以使社区发现更有价值的答案在顶部?
马丁·史密斯

Answers:


263

这是由于存在代码所依赖的类文件,并且该类文件在编译时存在而在运行时未找到。在构建时间和运行时类路径中寻找差异。


1
将源文件放在错误的名称空间/程序包下时,会发生此错误。我我可以把它放在任何地方,编译器很高兴。原来,我应该更加努力地让运行时变得快乐。
CenterOrbit

1
当我的服务器在文件上传期间内存不足时,就会出现此错误。每次尝试上传时,都会收到一个不同的错误。最终它告诉我我没有足够的堆空间。
James M. Lay

79
这个答案不一定是正确的,并且会误导许多人!请从下面的Jared中获得更好的答案。
Dave L.

4
@DaveL。谢谢!贾里德(Jared)有400多个投票的答案如下!带有-4上(下)投票的答案是远远高于它的答案。SO的答案排序逻辑有些混乱。
Saurabh Patil's

1
对于某人来说,这是一个长途跋涉,但是我遇到了此错误,因为相关的类包含一个用无效字符初始化的SimpleDateFormat(我中间用T代替了“ T”)。
Ryan D

816

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

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

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

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


30
感谢您提到NoClassDefFoundError的原因,这对我很有帮助!在我的情况下,抛出了ExceptionInInitializerError,这就是我发现静态块中错误的方式。
托马斯

@Jared,当我得到时Error: Could not find or load main class,它将分类为哪个错误类别?
维克拉姆

@ Pops:使语言更加冗长,以指定动词“ try”的对象:)
Jared

1
@Vikram的“找不到或加载主类”不是Java异常,它是由启动器(检查JAR和main manifest属性)引起的。
eckes

2
当类具有引发错误或异常的静态初始化时,也会引发ClassNotFoundException。他们可能应该为该事件选择其他名称。
coladict

124

这是说明的代码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;
}

3
原因是第一次尝试jvm后就已经知道它不起作用并第二次抛出不同的异常?
ikamen '18

@ikamen显然它已将SimpleCalculator除零后未成功的类初始化存储在某个地方?是否有人为此行为参考了官方文档?
ᴠɪɴᴄᴇɴᴛ

4
@PhilipRego不确定“纯” NoClassDefFoundError的含义。第一次new SimpleCalculator()调用时,您会收到一个由ArithmeticException引起的ExceptionInInitializerError。第二次调用时,new SimpleCalculator()您会得到一个NoClassDefFoundError,其纯度与其他任何类一样。关键是,由于运行时不在类路径上的SimpleCalculator.class以外的原因,您可以获得NoClassDefFoundError。
哈珀斯卡

36

Java中的NoClassDefFoundError

定义:

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

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

在此处输入图片说明

例子:

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

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

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

可能的解决方案:

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

资源:

解决NoClassDefFoundError的3种方法

java.lang.NoClassDefFoundError问题模式


1
好答案。我想我已经尝试了您提出的所有建议,但仍然存在该问题。由于jar与spring一起使用,我可以排除其中的一些,但java.sql似乎不喜欢它们(在我的情况下,Hana的sap db驱动程序)。
JE Carter II

它实际上称为System.getproperty(“ java.class.path”)
RIJIK

33

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

set classpath=%classpath%;axis.jar

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

set classpath=axis.jar;%classpath%;

4
有同样的问题。原来我用Java7编译了war文件,但是我的Tomcat安装使用的是Java6。我不得不更新我的环境变量
duvo

4
如果发生这种情况,那我就说Java一团糟。如果是,则+2。尚无法验证。如果发现为真,则会再次+1(在评论中)
超新星

7

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

假设我们有一个org.mypackage包含类的包:

  • HelloWorld(主类)
  • 技术支持
  • 实用程序类

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

文件结构将如下所示: 在此处输入图片说明

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


6

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

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

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

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


1
编写Servlet时,我发生了同样的事情(NoClassDefFoundError实际上是由引起的ExceptionInInitalizerError,这是由引起的DateTimeParseException)。这有点误导,不是吗?我知道他们可能有这样做的理由,但是至少要有一个小提示真是太好了,这NoClassDefFoundError是另一个例外的结果,而无需推断出它。仅ExceptionInInitializerError再次抛出将更加清楚。有时两者之间的联系可能并不那么明显。
巴特洛梅耶杰林斯基

5

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

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

它产生的输出显示已加载的类,以及加载该类的加载器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;
            }
        });
    }
}


5

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

  1. throw一个RuntimeExceptionstatic你的类的块Example
  2. 拦截它(或者,如果它就像在测试用例中抛出一样没关系)
  3. 尝试创建此类的实例 Example

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


当您NoClassDefFoundErrorsUNIT TESTS中看到时,这尤其重要。

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


4
这是现实生活中非常有用的建议。我只是在使用类属性初始化程序时遇到了同样的情况。您只有一次机会在日志中看到实际的问题。加载(或尝试尝试)该类后,您需要重新启动所有内容。
DailyFrankPeter

4

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

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

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



1

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

dexOptions {
        preDexLibraries false
        ...

1

NoClassDefFoundError静态初始化程序尝试加载运行时不可用的资源束时,也会发生这种情况,例如,受影响的类试图从META-INF目录加载但不在目录中的属性文件。如果您没有抓住NoClassDefFoundError,有时您将看不到完整的堆栈跟踪信息。为了克服这个问题,您可以暂时使用以下catch子句Throwable

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

这是不正确的。缺少资源不会给您这个错误。如果缺少课程,您只会得到它。
斯蒂芬·C

@StephenC也许我应该再强调一下这一部分,但是我写了for example a properties file that the affected class tries to load from the META-INF directory。这实际上发生在我身上,我能够NoClassDefFoundError通过添加缺少的属性文件来解决。我之所以添加此答案,恰恰是因为在上述情况下不会出现此错误。
ᴠɪɴᴄᴇɴᴛ

1
然后,您错过了解释中非常重要的内容,因为丢失的资源文件可能触发该异常的唯一方法是,如果您尝试在static初始化中加载资源文件,则会触发未检查的异常并导致类初始化。失败。从静态初始化传播的任何未经检查的异常都可以做到这一点。
斯蒂芬·C

如果我错了(即这不是由于static初始化失败而引起的),我将很想看到一个演示该行为的实际示例(即MCVE)。
Stephen C

1
@StephenC但是,您绝对正确:((我查找了遇到此问题的情况,它确实涉及试图加载资源束的静态初始化程序。我将扩大/更正原因的描述。感谢您指出这一点出来。
ᴠɪɴᴄᴇɴᴛ

1

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


0

如果有人因为java.lang.NoClassDefFoundError: org/apache/log4j/Logger错误而来到这里,在我的情况下,它的产生是因为我使用了log4j 2(但是我没有添加它附带的所有文件),而某些依赖库使用了log4j1。解决方案是添加Log4j 1.x网桥:log4j-1.2-api-<version>.jarlog4j 2随附的jar。log4j 2 迁移中的更多信息。


0

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

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

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


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


0

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


0

就我而言,由于JDK版本不匹配,导致出现此错误。当我尝试从Intelij运行该应用程序时无法正常工作,但随后从命令行运行了。这是因为Intelij试图使用已设置的Java 11 JDK运行它,但在命令行上却使用Java 8 JDK运行它。在“文件”>“项目结构”>“项目设置”>“ Project SDK”下切换该设置后,它对我有用。


0

这里的每个人都在谈论一些Java配置问题,JVM问题等,在我的情况下,该错误与这些主题完全无关,并且具有非常简单且易于解决的原因:我在Controller的端点上标注了错误的注释( Spring Boot应用程序)。


0

我在使用Liberty服务器的JavaEE中遇到了一个N​​oClassDefFoundError有趣的问题。我正在使用IMS资源适配器,而我的server.xml已经具有imsudbJXA.rar的资源适配器。当我为imsudbXA.rar添加新适配器时,对于DLIException,IMSConnectionSpec或SQLInteractionSpec的实例对象,我将开始收到此错误。我不知道为什么,但是我通过仅使用imsudbXA.rar为我的工作创建了新的server.xml来解决了该问题。我确定在server.xml中使用多个资源适配器是可以的,但是我没有时间去研究它。


-1

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

问题消失了。


-1

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

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

例如,

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

-6

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

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


4
用投票最多的答案来解释,当您第一次编译时,文件在那里,然后您删除了一些文件,这些类被删除了,因此在运行时,您得到了ClassNotFound,然后又将它们还原,但Eclipse却没有请注意,因此仍然缺少生成的类,但是在重新启动Eclipse之后,刷新了工作空间,并且这些类再次可用,但是通常这不是解决方案或解决方法,该解决方案是在运行时中查找缺少哪个类/ jar类路径。
Jose Manuel Gomez Alvarez

-7

确保在module:app和中匹配module:lib

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

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

3
您的解决方案与这个常见问题有何关系?
塔维·伊尔维斯

样本配置不平衡(三个{s和两个})。你能修好它吗?
彼得·莫滕森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.