首页 文章

为什么我在Java中获得NoClassDefFoundError?

提问于
浏览
423

当我运行我的Java应用程序时,我得到 NoClassDefFoundError . 这通常是什么原因?

20 回答

  • 97

    这是因为当您的代码依赖于类文件并且它在编译时出现但在运行时未找到时 . 查找构建时和运行时类路径的差异 .

  • 5

    虽然这可能是由于编译时和运行时之间的类路径不匹配,但它不一定是真的 .

    在这种情况下,重要的是要保持两到三个不同的例外:

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

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

  • 4

    这是用于说明 java.lang.NoClassDefFoundError 的代码 . 有关详细说明,请参阅Jared's answer .

    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;
    }
    
  • -1

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

    set classpath=%classpath%;axis.jar
    

    我能够通过使用以下方式获取正确的版本:

    set classpath=axis.jar;%classpath%;
    
  • 27

    NoClassDefFoundError In Java

    Definition:

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

    • 如果在编译期间存在类,但在运行时期间在java类路径中不可用 .

    enter image description here

    Examples:

    • 该类不在Classpath中,没有确定的知道它的镜头方式,但很多时候你可以看一下打印System.getproperty("java.classpath")并且它会从那里打印类路径你至少可以知道你的实际运行时类路径 .

    • NoClassDefFoundError的一个简单示例是类属于缺少的JAR文件,或者JAR没有添加到类路径中,或者有时jar的名称已被某人更改,就像在我的情况下,我的一位同事将tibco.jar更改为tibco_v3.jar和程序用java.lang.NoClassDefFoundError失败了,我想知道出了什么问题 .

    • 只是尝试使用显式-classpath选项运行您认为可以使用的类路径,如果它正在工作,那么这是一个确定的短标志,有人正在重写java类路径 .

    • JAR文件的权限问题也可能导致Java中的NoClassDefFoundError .

    • 错误配置上的错误也可能导致Java中的NoClassDefFoundError .

    • 当你在包中定义的编译类在加载时不会出现在同一个包中,就像在JApplet中一样,它将在Java中抛出NoClassDefFoundError .

    Possible Solutions:

    • 该类在Java Classpath中不可用 .

    • 如果您在J2EE环境中工作,那么多个Classloader中的Class的可见性也会导致java.lang.NoClassDefFoundError,请参阅示例和场景部分进行详细讨论 .

    • 检查日志文件中的java.lang.ExceptionInInitializerError . 由于静态初始化失败而导致的NoClassDefFoundError非常常见 .

    • 因为NoClassDefFoundError是java.lang.LinkageError的子类,所以如果其中一个依赖项(如本机库)可能不可用,也会出现这种情况 .

    • 任何启动脚本都会覆盖Classpath环境变量 .

    • 您可能正在使用jar命令运行程序,并且未在清单文件的ClassPath中定义类属性 .

    资源:

    3 ways to solve NoClassDefFoundError

    java.lang.NoClassDefFoundError Problem patterns

  • 2

    我正在使用带有MavenSpring Framework并在我的项目中解决了这个错误 .

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

    Spring没有给我一个关于运行时失败的哪一行的完整堆栈跟踪 . 它简单地说 NoClassDefFoundError . 但是当我将它作为本机Java应用程序执行(将其从MVC中取出)时,它给出了 ExceptionInInitializerError 这是真正的原因,这就是我如何跟踪错误 .

    @ xli的回答让我深入了解了我的代码可能出错的地方 .

  • 0

    当运行时类加载器加载的类无法访问java rootloader已经加载的类时,我得到NoClassFoundError . 因为不同的类加载器位于不同的安全域中(根据java),jvm将不允许在运行时加载器地址空间中解析已由rootloader加载的类 .

    用'java -javaagent:tracer.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;
                }
            });
        }
    }
    
  • 1

    这是我到目前为止发现的best solution .

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

  • 0

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

    请参阅堆栈溢出问题How to increase the Java stack size? .

  • 30

    下面的技术帮了我很多次:

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

    其中TheNoDefFoundClass是由于您对程序使用的同一个库的旧版本的偏好而可能“丢失”的类 . 当客户端软件被部署到一个占主导地位的容器中时,最常发生这种情况,它拥有自己的类加载器和大量最流行的库的古老版本 .

  • 211

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

    • throw a RuntimeException 在您 class 的 static 区块 Example

    • 拦截它(或者如果只是在一个测试用例中引发它并不重要)

    • 尝试创建此类的实例 Example

    static class Example {
        static {
            thisThrowsRuntimeException();
        }
    }
    
    static class Simulation {
    
        Simulation() {
            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 时,这一点尤为重要 .

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

  • 669

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

  • 0

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

    就我而言,问题是Eclipse无法区分同一项目的两个不同副本 . 我有一个锁定在trunk(SVN版本控制)上,另一个一次在一个分支中工作 . 我尝试将工作副本中的一个更改作为JUnit测试用例,其中包括将私有内部类提取为自己的公共类,当它正在工作时,我打开项目的另一个副本来环顾其他一些需要更改的部分代码 . 在某些时候, NoClassDefFoundError 突然抱怨私人内部阶级不存在;双击堆栈跟踪将我带到错误的项目副本中的源文件 .

    关闭项目的主干副本并再次运行测试用例可以解决问题 .

  • -1

    未经检查的 Java version 要求可能导致此错误 .

    在我的情况下,我能够解决此错误,而通过使用SDKMAN!从Java 9切换到Java 8来构建一个备受瞩目的开源项目 .

    sdk list java
    sdk install java 8u152-zulu
    sdk use java 8u152-zulu
    

    然后按如下所述进行全新安装 .


    当使用 Maven 作为你的构建工具时,做一个干净的'install' build with testing disabled 有时会很有帮助 - 而且通常很令人满意 .

    mvn clean install -DskipTests
    

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

    mvn test
    
  • 6

    我通过禁用所有模块的preDexLibraries来修复我的问题:

    dexOptions {
            preDexLibraries false
            ...
    
  • 3

    Java无法在运行时找到A类 . A类是来自不同工作空间的maven项目ArtClient . 所以我将ArtClient导入我的Eclipse项目 . 我的两个项目是使用ArtClient作为依赖项 . 我将库引用更改为这些项目的引用(构建路径 - >配置构建路径) .

    而问题消失了 .

  • -1

    我有同样的问题,我有很多小时的股票 .

    我找到了解决方案 . 在我的例子中,由于这个原因定义了静态方法 . JVM无法创建该类的另一个对象 .

    例如,

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

    当某些资源在运行时不可用时也会发生 NoClassDefFoundError ,例如受影响的类尝试从 META-INF 目录加载的属性文件 . 如果你没有 grab NoClassDefFoundError ,有时你将无法看到完整的堆栈跟踪;要克服这一点,你可以暂时使用 Throwablecatch

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

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

    我的解决方案是:重启Eclipse . 从那以后我再没有看到这个消息:-)

  • 0

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

    android {
        compileSdkVersion 23
        buildToolsVersion '22.0.1'
        packagingOptions {
        }
    
        defaultConfig {
            minSdkVersion 17
            targetSdkVersion 23
            versionCode 11
            versionName "2.1"
        }
    

相关问题