为什么在Java中出现NoClassDefFoundError错误?

665

当我运行我的Java应用程序时,出现了NoClassDefFoundError。通常这是什么原因导致的?


1
我相信如果您没有使用正确的语法运行Java程序,也会发生这种情况。例如,您必须使用完整的包名称(即my.package.myClass)从根bin文件夹调用类。如果可能的话,我会更具体,但我不是很擅长Java。我只记得自己犯过几次这样的错误。 - frank hadder
32个回答

1034

虽然这可能是由于编译时和运行时之间的类路径不匹配,但并不一定如此。

在这种情况下,我们在头脑中要清晰区分两到三个不同的异常:

  1. java.lang.ClassNotFoundException 该异常表示未在类路径上找到该类。这意味着我们试图加载类定义,但该类不存在于类路径上。

  2. java.lang.NoClassDefFoundError 该异常表示JVM在其内部类定义数据结构中查找一个类的定义,但未找到它。这与说它无法从类路径加载不同。通常,这表明我们之前尝试从类路径加载类,但由于某些原因失败了 - 现在我们再次尝试使用该类(因此需要加载它,因为上次加载失败了),但我们甚至不会尝试加载它,因为我们之前加载失败(并且合理地怀疑我们将再次加载失败)。先前的失败可能是ClassNotFoundException或ExceptionInInitializerError(指静态初始化块中的失败)或任何其他问题。重点是,NoClassDefFoundError并不一定是类路径问题。


59
感谢提到 NoClassDefFoundError 的原因,这对我帮助很大!在我的情况下,在静态块中抛出了 ExceptionInInitializerError,这就是我发现错误的方式。 - Thomas
@Pops:将语言更加冗长以指定动词“try”的对象 :) - Jared
在加载过程中也可能出现ClassCircularityErrorClassFormatError:http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.2.1 - Pacerier
1
@Vikram,“找不到或加载主类”不是Java异常,而是由启动器引起的(它检查JAR和主清单属性)。 - eckes
4
当一个类的静态初始化抛出错误或异常时,也会抛出ClassNotFoundException异常。他们可能应该为这个事件选择一个不同的名称。 - coladict
显示剩余7条评论

304

当您的代码依赖的类文件在编译时存在,但在运行时未找到时,会发生这种情况。请查看构建时间和运行时类路径之间的差异。


1
当我将源文件放在错误的命名空间/包下时,出现了这个错误。我认为我可以把它放在任何地方,编译器也很高兴。结果证明,我应该更加勤奋,以使运行时也感到高兴。 - CenterOrbit
2
我曾经在服务器文件上传时遇到过这个错误。每次尝试上传时都会出现不同的错误。最终,它告诉我没有足够的堆空间。 - James M. Lay
133
这个答案不一定正确,会误导很多人!请参考下面Jared提供的更好的答案。 - Dave L.
5
@DaveL. 谢谢!Jared的回答获得了400多个赞,但排名远低于一个得到-4个赞(或者是踩?)的回答。SO的回答排序逻辑有些不对劲。 - Saurabh Patil
1
类名(NoClassDefFoundError)表示找到并加载了类文件,但无法转换为JVM类定义,可能是由于静态初始化器中的任何未捕获异常或放置在其命名空间暗示的不同位置(jar或文件夹中的子路径,错误的文件名大小写)导致的。 - Daniel Yang
显示剩余4条评论

155

以下是代码,用于说明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;
}

4
原文:And the reason is that after first try jvm already knows its not going to work and throw different exception second time?翻译:原因在于,在第一次尝试后,JVM已经知道它不会起作用,并在第二次抛出不同的异常? - ikamen
1
@ikamen 显然,在除以零后,它在某个地方存储了SimpleCalculator的初始化失败。有人有关于此行为的官方文档参考吗? - ᴠɪɴᴄᴇɴᴛ
7
不确定您所说的“纯”的NoClassDefFoundError是什么意思。第一次调用new SimpleCalculator()时,会出现一个具有算术异常原因的ExceptionInInitializerError。第二次调用new SimpleCalculator()时,您会像其他任何情况一样得到一个非常“纯”的NoClassDefFoundError。关键在于,您可能会由于运行时存在SimpleCalculator.class之外的原因而获得NoClassDefFoundError。 - harperska

51

Java中的NoClassDefFoundError错误

定义:

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

  2. 如果一个类在编译时存在,但在Java类路径在运行时不可用。

enter image description here

示例:

  1. 如果类不在Classpath中,没有一种确定的方法可以知道它,但是很多时候你可以查看打印出来的System.getproperty("java.classpath")来获取实际运行时classpath的概念。
  2. NoClassDefFoundError的一个简单例子是类属于丢失的JAR文件或JAR未添加到classpath中,有时JAR的名称已被某人更改,例如在我的情况下,我的一个同事将tibco.jar更改为tibco_v3.jar,程序失败并显示java.lang.NoClassDefFoundError,我想知道出了什么问题。

  3. 尝试使用显式-classpath选项运行您认为会起作用的classpath,如果它可以工作,则这是某人覆盖java classpath的明确迹象。

  4. 在Java中,JAR文件的权限问题也可能导致NoClassDefFoundError。
  5. XML配置上的拼写错误也可能导致Java中的NoClassDefFoundError。
  6. 当您编译的类定义在包中,并且在加载时与同一包不一致,例如在JApplet的情况下,它会抛出Java中的NoClassDefFoundError。

可能的解决方案:

  1. Java类路径中不存在该类。
  2. 如果您正在使用J2EE环境,则类在多个类加载器之间的可见性也可以导致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驱动程序)。 - J E Carter II
2
它实际上被称为System.getproperty("java.class.path")。 - GRASBOCK
问题仍未解决,但这是非常有用的信息。 - BeHappy

34

我发现有时候在运行时,编译的代码与类的不兼容版本产生NoClassDefFound错误。我回忆起来的具体实例是在使用Apache Axis库时出现的。我的运行时类路径上实际上有两个版本,它选择了过时和不兼容的版本而不是正确的版本,导致了NoClassDefFound错误。这是在一个命令行应用程序中,我使用了类似于这样的命令。

set classpath=%classpath%;axis.jar

通过使用以下方法,我成功让它选择正确的版本:

set classpath=axis.jar;%classpath%;

4
我遇到了同样的问题。原来我使用Java7编译了WAR文件,但我的Tomcat安装使用的是Java6。我需要更新我的环境变量。 - duvo
4
如果事情发展成那样,我会说Java乱了。如果属实的话,加2分。目前还无法确认。如果发现是真的,会再次加1分(在评论中)。 - supernova

9

这是我目前找到的最佳解决方案

假设我们有一个名为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


9
当你在以下情况下时,可能会看到很多NoClassDefFoundErrors
  1. 在类Examplestatic块中抛出RuntimeException
  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
    }
}

当静态代码块RuntimeException中出现NoClassDefError时,会抛出ExceptionInInitializerError异常。


单元测试中出现NoClassDefFoundErrors时,这种情况尤其重要。

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


4
这是现实生活中非常实用的建议。我刚遇到了类属性初始化器相同的情况。您只有一次机会在日志中看到实际问题。一旦类被加载(或者至少尝试加载),您需要重新启动一切。 - DailyFrankPeter

6

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

类中发生了运行时错误。 我正在将属性读取为整数,但当它从属性文件中读取值时,其值是双精度浮点数。

Spring没有给出完整的堆栈跟踪以指示运行时失败的代码行。 它只是说NoClassDefFoundError。 但是,当我将其作为本机Java应用程序执行(将其取出MVC),它会产生真正的原因ExceptionInInitializerError,这就是我追踪错误的方式。

@xli的答案让我更好地理解了我的代码可能存在的问题。


2
当我编写一个Servlet时,也发生了同样的事情(NoClassDefFoundError实际上是由ExceptionInInitializerError引起的,而这又是由DateTimeParseException引起的)。这有点误导人,不是吗?我知道他们可能有他们的理由让它变成这样,但是至少给出一个小提示,说明NoClassDefFoundError是另一个异常的结果,而无需推断。只是再次抛出ExceptionInInitializerError会更清晰明了。有时两者之间的联系可能并不那么明显。 - Bartłomiej Zieliński

5
当运行时类加载器无法访问已由Java根加载器加载的类时,我会收到NoClassFoundError错误。由于不同的类加载器位于不同的安全域中(根据Java),因此JVM不会允许在运行时加载器地址空间中解析已由根加载器加载的类。

使用“java-javaagent:tracer.jar [YOUR java ARGS]”运行程序

它会产生输出,显示加载的类和加载该类的加载器环境。这对追踪无法解决类的原因非常有帮助。

// 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;
            }
        });
    }
}

1
链接已失效。请尝试使用存档版本:http://web.archive.org/web/20131216000019/https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5 - avgvstvs

4
下面的技巧帮助过我很多次:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

其中,TheNoDefFoundClass 是一个类,可能会因为程序使用旧版本的同一库而“丢失”。这种情况最常见于客户端软件部署到支持自己的类加载器和大量古老版本的流行库的主流容器中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接