为什么在Java中收到NoClassDefFoundError?

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


#1楼

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

#2楼

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

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

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

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


#3楼

当运行时类加载器加载的类无法访问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;
            }
        });
    }
}

#4楼

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

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

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

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

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

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


#5楼

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

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


#6楼

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


#7楼

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

set classpath=%classpath%;axis.jar

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

set classpath=axis.jar;%classpath%;

#8楼

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

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

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

#9楼

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

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

例如,

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

#10楼

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

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

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


#11楼

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问题模式


#12楼

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

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


#13楼

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


#14楼

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

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

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


#15楼

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

问题消失了。


#16楼

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

dexOptions {
        preDexLibraries false
        ...

#17楼

此错误可能是由于未经检查的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

#18楼

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

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

#19楼

在以下情况中,您可能会看到很多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


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

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


#20楼

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


#21楼

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


#22楼

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

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

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

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


#23楼

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值