为什么Java中会出现NoClassDefFoundError?

为什么Java中会出现NoClassDefFoundError?,java,noclassdeffounderror,Java,Noclassdeffounderror,当我运行Java应用程序时,我得到一个NoClassDefFoundError。这通常是什么原因造成的?这是由于存在代码所依赖的类文件,并且该类文件在编译时存在,但在运行时找不到。查找构建时和运行时类路径中的差异 我发现,当使用运行时发现的类的不兼容版本编译代码时,有时会出现NoClassDefFound错误。我记得的具体实例是ApacheAxis库。实际上,我的运行时类路径上有两个版本,它拾取的是过期且不兼容的版本,而不是正确的版本,导致NoClassDefFound错误。这是在一个命令行应用

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

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

我发现,当使用运行时发现的类的不兼容版本编译代码时,有时会出现NoClassDefFound错误。我记得的具体实例是ApacheAxis库。实际上,我的运行时类路径上有两个版本,它拾取的是过期且不兼容的版本,而不是正确的版本,导致NoClassDefFound错误。这是在一个命令行应用程序中,我使用了与此类似的命令

set classpath=%classpath%;axis.jar
我能够通过使用以下工具使其获得正确的版本:

set classpath=axis.jar;%classpath%;

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

在这种情况下,在我们的头脑中保持两个或三个不同的例外是很重要的:

  • java.lang.ClassNotFoundException
    此异常表示在类路径上找不到该类。这表明我们试图加载类定义,而类路径上不存在该类

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


  • 下面是说明
    java.lang.NoClassDefFoundError
    的代码。详细解释请参见

    NoClassDefFoundErrorDemo.java

    SimpleCalculator.java

    我正在使用,并在我的项目中解决了这个错误

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

    Spring没有给出运行时失败的行的完整堆栈跟踪。 它只是说
    NoClassDefFoundError
    。但当我将其作为本地Java应用程序执行时(将其从MVC中删除),它给出了
    异常InInitializeRerror
    ,这是真正的原因,也是我跟踪错误的方式


    @xli的回答让我洞察了代码中可能存在的错误。

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

    使用“java-javaagent:tracer.jar[您的java参数]运行您的程序”

    它生成显示加载的类和加载该类的loader 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;
                }
            });
        }
    }
    
    这是我到目前为止找到的最新的

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

    • HelloWorld(主类)
    • 支持类
    • 实用类
    定义此包的文件物理存储在目录
    D:\myprogram
    (在Windows上)或
    /home/user/myprogram
    (在Linux上)下

    文件结构如下所示:

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

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


    我的解决方案是:重新启动Eclipse。从那以后,我再也没有看到过这条消息:-)

    确保在
    模块:app
    模块:lib
    中匹配这条消息:

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

    我也有同样的问题,而且我有好几个小时的存货

    我找到了解决办法。在我的例子中,有一个静态方法就是由此定义的。JVM无法创建该类的另一个对象

    比如说,

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

    下面的技巧多次帮助了我:

    System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
    
    其中,Thenodeffound类是由于您的程序使用的相同库的较旧版本而可能“丢失”的类。这种情况最常发生在客户端软件部署到一个主要容器中时,该容器配备有自己的类加载器和大量最流行的libs的古老版本。

    NoClassDefFoundError In Java

    定义:

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

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

  • 示例:

  • 该类不在类路径中,没有确切的方法知道它,但很多时候,您只需查看一下打印System.getproperty(“java.Classpath”),它就会打印类路径,从那里您至少可以了解实际运行时的类路径
  • 一个简单的例子
    private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
    
    System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
    
    dexOptions {
            preDexLibraries false
            ...
    
    sdk list java
    sdk install java 8u152-zulu
    sdk use java 8u152-zulu
    
    mvn clean install -DskipTests
    
    mvn test
    
    try {
        // Statement(s) that cause(s) the affected class to be loaded
    } catch (Throwable t) {
        Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
    }
    
    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
        }
    }
    
    package valentines;
    
    import java.math.BigInteger;
    import java.util.ArrayList;
    
    public class StudentSolver {
        public static ArrayList<Boolean> solve(ArrayList<ArrayList<BigInteger>> problems) {
            //DOING WORK HERE
            
        }
        public static void main(String[] args){
            //TESTING SOLVE FUNCTION
        }
        
    }
    
    MyClass myClass = new MyClass();
    
    MyClass myClass = (MyClass) Class.forName("MyClass").newInstance();