提问人:John Meagher 提问时间:8/29/2008 最后编辑:Duncan JonesJohn Meagher 更新时间:11/9/2023 访问量:1094743
为什么我在 Java 中收到 NoClassDefFoundError?
Why am I getting a NoClassDefFoundError in Java?
答:
当代码依赖于一个类文件,并且该类文件在编译时存在但在运行时找不到时,就会导致这种情况。查找生成时和运行时类路径的差异。
评论
我发现有时当使用运行时发现的不兼容版本的类编译代码时,我会得到 NoClassDefFound 错误。我记得的具体实例是 apache 轴库。我的运行时类路径上实际上有 2 个版本,它选择了过时和不兼容的版本,而不是正确的版本,从而导致 NoClassDefFound 错误。这是在一个命令行应用程序中,我使用了与此类似的命令。
set classpath=%classpath%;axis.jar
我能够通过使用以下方法让它选择正确的版本:
set classpath=axis.jar;%classpath%;
评论
虽然这可能是由于编译时和运行时之间的类路径不匹配,但事实并非如此。
在这种情况下,重要的是要将两个或三个不同的例外情况直接记在脑海中:
java.lang.ClassNotFoundException
此异常表示在类路径上找不到该类。这表明我们正在尝试加载类定义,并且类路径上不存在该类。java.lang.NoClassDefFoundError
此异常表示 JVM 在其内部类定义数据结构中查找类的定义,但未找到它。这与说它不能从类路径加载不同。通常,这表明我们之前尝试从类路径加载一个类,但由于某种原因它失败了 - 现在我们尝试再次使用该类(因此需要加载它,因为它上次失败了),但我们甚至不会尝试加载它,因为我们之前加载它失败了(并且有理由怀疑我们会再次失败)。较早的故障可能是 ClassNotFoundException 或 ExceptionInInitializerError(指示静态初始化块中的故障)或任何其他问题。关键是,NoClassDefFoundError 不一定是类路径问题。
评论
Error: Could not find or load main class
下面是用于说明的代码。详细解释请看 Jared 的回答。java.lang.NoClassDefFoundError
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;
}
评论
SimpleCalculator
new SimpleCalculator()
new SimpleCalculator()
我正在将 Spring Framework 与 Maven 一起使用,并在我的项目中解决了这个错误。
类中存在运行时错误。我以整数形式读取属性,但是当它从属性文件中读取值时,它的值是双倍的。
Spring 没有给我运行时失败的哪一行的完整堆栈跟踪。
它只是说.但是当我将其作为本机 Java 应用程序执行(将其从 MVC 中取出)时,它给出了真正的原因,这就是我跟踪错误的方式。NoClassDefFoundError
ExceptionInInitializerError
@xli的回答让我深入了解了我的代码中可能存在的问题。
评论
NoClassDefFoundError
ExceptionInInitalizerError
DateTimeParseException
NoClassDefFoundError
ExceptionInInitializerError
当运行时类加载器加载的类无法访问 java rootloader 已加载的类时,我得到 NoClassFoundError。因为不同的类装入器位于不同的安全域中(根据 java),所以 jvm 不允许在运行时装入器地址空间中解析已经由 rootloader 加载的类。
使用“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;
}
});
}
}
评论
这是我迄今为止找到的最好的解决方案。
假设我们有一个名为 包含类的包:org.mypackage
- HelloWorld(主类)
- 支持类
- Util类
定义此包的文件物理存储在目录下(在 Windows 上)或(在 Linux 上)。D:\myprogram
/home/user/myprogram
当我们调用 Java 时,我们指定要运行的应用程序的名称:.但是,我们还必须告诉 Java 在哪里查找定义我们包的文件和目录。因此,要启动程序,我们必须使用以下命令:org.mypackage.HelloWorld
我也有同样的问题,而且我库存了好几个小时。
我找到了解决方案。就我而言,因此定义了静态方法。JVM 无法创建该类的另一个对象。
例如
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
下面的技术帮助了我很多次:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
其中 TheNoDefFoundClass 是可能由于对程序使用的同一库的旧版本的首选而“丢失”的类。这种情况最常发生,当客户端软件被部署到一个占主导地位的容器中时,它有自己的类加载器和最流行的库的大量旧版本。
Java 中的 NoClassDefFoundError
定义:
Java 虚拟机无法在运行时找到在编译时可用的特定类。
如果某个类在编译时存在,但在运行时在 java 类路径中不可用。
例子:
- 该类不在 Classpath 中,没有确定的方法来了解它,但很多时候您可以查看打印 System.getproperty(“java.classpath”),它将从那里打印类路径,您至少可以了解实际的运行时类路径。
NoClassDefFoundError 的一个简单示例是 class 属于丢失的 JAR 文件,或者 JAR 未添加到类路径中,或者有时 jar 的名称已被某人更改,例如在我的案例中,我的一位同事已将tibco.jar更改为 tibco_v3.jar 并且程序失败并显示 java.lang.NoClassDefFoundError,我想知道出了什么问题。
只需尝试使用显式 -classpath 选项运行您认为可以工作的类路径,如果它有效,那么这肯定是一个简短的迹象,表明有人正在覆盖 java classpath。
- JAR 文件的权限问题也可能导致 Java 中的 NoClassDefFoundError。
- XML 配置上的拼写错误也可能导致 Java 中的 NoClassDefFoundError。
- 当在包中定义的编译类在加载时不出现在同一个包中时,就像 JApplet 一样,它会在 Java 中抛出 NoClassDefFoundError。
可能的解决方案:
- 该类在 Java 类路径中不可用。
- 如果您在 J2EE 环境中工作,那么 Class 在多个 Classloader 中的可见性也可能导致 java.lang.NoClassDefFoundError,请参阅示例和场景部分进行详细讨论。
- 检查日志文件中的 java.lang.ExceptionInInitializerError。由于静态初始化失败导致的 NoClassDefFoundError 很常见。
- 因为 NoClassDefFoundError 是 java.lang.LinkageError 的子类,所以如果其中一个依赖项(如本机库)可能不可用,它也可能出现。
- 任何启动脚本都会覆盖 Classpath 环境变量。
- 您可能正在使用 jar 命令运行程序,并且未在清单文件的 ClassPath 属性中定义类。
资源:
解决 NoClassDefFoundError 的 3 种方法
java.lang.NoClassDefFoundError 问题模式
评论
如果您有生成代码(EMF 等),则可能会有太多的静态初始化器占用所有堆栈空间。
请参阅堆栈溢出问题如何增加 Java 堆栈大小?。
评论
如果有人因为错误而来到这里,就我而言,它是因为我使用了 log4j 2(但我没有添加它附带的所有文件)而产生的,并且一些依赖库使用了 log4j 1。解决方案是添加 Log4j 1.x 桥:log4j 2 附带的 jar。log4j 2 迁移中的详细信息。java.lang.NoClassDefFoundError: org/apache/log4j/Logger
log4j-1.2-api-<version>.jar
同一项目的两个不同签出副本
就我而言,问题在于 Eclipse 无法区分同一项目的两个不同副本。我有一个锁定在主干(SVN 版本控制)上,另一个一次在一个分支中工作。我尝试了工作副本中的一个更改作为 JUnit 测试用例,其中包括将一个私有内部类提取为一个独立的公共类,当它工作时,我打开项目的另一个副本来查看代码中需要更改的其他部分。在某个时候,突然出现抱怨私人内部阶级不在那里;双击堆栈跟踪将我带到了错误项目副本中的源文件。NoClassDefFoundError
关闭项目的主干副本并再次运行测试用例解决了这个问题。
Java 无法在运行时找到类 A。 类 A 位于来自不同工作区的 maven 项目 ArtClient 中。 因此,我将 ArtClient 导入到我的 Eclipse 项目中。 我的两个项目使用 ArtClient 作为依赖项。 我将库引用更改为这些项目引用(构建路径 ->配置构建路径)。
问题就消失了。
我通过禁用所有模块的 preDexLibraries 解决了我的问题:
dexOptions {
preDexLibraries false
...
此错误可能是由未经检查的 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
NoClassDefFoundError
当静态初始值设定项尝试加载运行时中不可用的资源包时,也可能发生这种情况,例如,受影响的类尝试从目录加载但不存在的属性文件。如果不抓住,有时您将无法看到完整的堆栈跟踪;为了克服这个问题,您可以暂时使用以下子句:META-INF
NoClassDefFoundError
catch
Throwable
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);
}
评论
for example a properties file that the affected class tries to load from the META-INF directory
NoClassDefFoundError
static
static
一个有趣的例子是,您可能会看到很多情况,即当您:NoClassDefFoundErrors
throw
a 在班级的块中RuntimeException
static
Example
- 拦截它(或者如果它无关紧要,就像它被扔在测试用例中一样)
- 尝试创建此类的实例
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
评论
当我没有在项目的 Java 构建路径的“Order and Export”选项卡上导出类时,我收到了 NoClassDefFound 错误。确保在添加到项目构建路径的任何依赖项的“Order and Export”选项卡中勾选。请参阅 Eclipse 警告:XXXXXXXXXXX.jar将不会导出或发布。可能会产生运行时 ClassNotFoundExceptions。
也可能是因为您从具有特定包名称的 IDE 中复制了代码文件,并且想要尝试使用终端运行它。您必须先从代码中删除包名称。 这发生在我身上。
当我将另一个模块的 Maven 依赖项添加到我的项目中时,我收到了这个错误,这个问题最终通过添加到我的程序的 JVM 选项(自 JDK5.0 以来默认为 1 兆字节)解决了这个问题。据信该程序没有足够的堆栈来加载类。-Xss2m
就我而言,由于JDK版本不匹配,我收到了此错误。当我尝试从 Intelij 运行应用程序时,它不起作用,但随后从命令行运行它起作用了。这是因为 Intelij 尝试使用已设置的 Java 11 JDK 运行它,但在命令行上,它使用 Java 8 JDK 运行。在 Project SDK > > Project Structure > Project Settings 下切换该设置后,它对我有用。
每个人都在这里谈论一些 Java 配置问题、JVM 问题等,就我而言,错误与这些主题完全无关,并且有一个非常琐碎且易于解决的原因:我在控制器(Spring Boot 应用程序)的端点上有一个错误的注释。
我在使用 Liberty 服务器的 JavaEE 中遇到了一个有趣的 NoClassDefFoundError 问题。我正在使用 IMS 资源适配器,而我的server.xml已经有用于imsudbJXA.rar的资源适配器。 当我为 imsudbXA.rar 添加新的适配器时,我会开始为 DLIException、IMSConnectionSpec 或 SQLInteractionSpec 的实例对象收到此错误。 我不知道为什么,但我通过仅使用imsudbXA.rar为我的工作创建新server.xml来解决它。我确信在server.xml中使用多个资源适配器是可以的,我只是没有时间研究这个问题。
更新 [https://www.infoq.com/articles/single-file-execution-java11/]:
在 Java SE 11 中,您可以选择启动单个源代码文件 直接,无需中间编译。只是为了您的方便, 这样像你这样的新手就不必运行 javac + java(当然, 让他们感到困惑,为什么会这样)。
我遇到了这个错误,但无法根据这个线程找出解决方案,而是自己解决了。
对于我的问题,我正在编译以下代码:
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
}
}
然后,我在类似于 /ProjectName/valentines 的文件夹结构中编译此代码
编译它工作正常,但试图执行:java StudentSolver
我收到NoClassDefError。
为了解决这个问题,我只是删除了:package valentines;
我不是很精通 java 包之类的东西,但这就是我修复错误的方式,如果其他人已经回答了这个问题,那么很抱歉,但我无法将其解释为我的问题。
我在尝试在 Tomcat/JBOSS 服务器上部署应用程序时收到 NoClassDefFoundError。我使用不同的依赖项来解决问题,但一直收到相同的错误。将所有 javax.* 依赖项标记为 pom.xml 中提供,而 war 实际上没有依赖项。尽管如此,问题还是不断出现。
终于意识到 src/main/webapps/WEB-INF/classes 的 classes 文件夹被复制到我的战争中,所以这个类被复制的不是编译的类,因此没有依赖项更改可以解决问题。
因此,如果复制了任何以前编译的数据,请小心,删除类文件夹并重新编译后,它起作用了..
Java ClassNotFoundException 与 NoClassDefFoundError
静态与动态类加载
Static(Implicit) class loading
- 引用、实例化或继承的结果。
MyClass myClass = new MyClass();
Dynamic(Explicit) class loading
是 Class.forName()、loadClass()、findSystemClass() 的结果
MyClass myClass = (MyClass) Class.forName("MyClass").newInstance();
每个类都有一个 which 使用这就是为什么ClassLoader
loadClass(String name);
explicit class loader uses implicit class loader
NoClassDefFoundError
是 的一部分。这是为了保证在编译期间呈现了这个类,但现在(在运行时)它不存在了。explicit class loader
Error
ClassNotFoundException
是 的一部分。它应该在另外可以使用的场景中具有弹性 - 例如反射。implicit class loader
Exception
我的解决方案是“利用”缺少的特定类的类路径内容。就我而言,我有 2 个依赖项,虽然我能够使用 javac 成功编译......,但我无法使用 java ...运行生成的类文件,因为 BouncyCastle jar 中的 Dynamic 类无法在运行时加载。
javac --classpath "ext/commons-io-2.11.0;ext/bc-fips-1.0.2.3" hello.java
因此,在编译时和运行时,JVM 知道在哪里获取 Apache Commons 和 BouncyCastle 依赖项,但是,在运行它时,我得到了
Error: Unable to initialize main class hello
Caused by: java.lang.NoClassDefFoundError:
org/bouncycastle/jcajce/provider/BouncyCastleFipsProvider
因此,我根据类路径在同一位置手动创建了一个名为 ext 的新文件夹,然后我放置了 BouncyCastle jar 以确保在运行时可以找到它。您可以将 jar 相对于类文件或 jar 文件放置,只要生成的清单具有指定的 jar 位置即可。注意:我只需要使用一个包含缺少的类文件的 jar。
对我来说,问题是由于在 pom 中添加了不正确的依赖项。要检查这是否是您的问题,请运行,它应该会标记此问题。mvn clean verify
评论