我在运行 Java 应用程序时收到 NoClassDefFoundError
。这通常是什么原因?
虽然这可能是由于编译时和运行时之间的类路径不匹配,但这不一定是真的。
在这种情况下,将两个或三个不同的例外直接放在我们的脑海中是很重要的:
java.lang.ClassNotFoundException 此异常表示在类路径中找不到该类。这表明我们正在尝试加载类定义,并且类路径中不存在该类。 java.lang.NoClassDefFoundError 该异常表示JVM在其内部类定义数据结构中查找类的定义,但没有找到。这与说它无法从类路径加载不同。通常这表明我们之前尝试从类路径加载一个类,但由于某种原因它失败了 - 现在我们试图再次使用该类(因此需要加载它,因为它上次失败了),但是我们'甚至不会尝试加载它,因为我们之前未能加载它(并且有理由怀疑我们会再次失败)。较早的失败可能是 ClassNotFoundException 或 ExceptionInInitializerError(指示静态初始化块中的失败)或任何数量的其他问题。关键是,NoClassDefFoundError 不一定是类路径问题。
当您的代码依赖于一个类文件并且它在编译时存在但在运行时找不到时会导致这种情况。寻找构建时间和运行时类路径的差异。
这是说明 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();
}
}
简单计算器.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
SimpleCalculator
的不成功的类初始化?有人对此行为的官方文档有参考吗?
new SimpleCalculator()
时,您会得到一个 ExceptionInInitializerError,它由 ArithmeticException 引起。第二次调用 new SimpleCalculator()
时,您得到的 NoClassDefFoundError 与任何其他错误一样纯。关键是您可能会因为 SimpleCalculator.class 在运行时不在类路径上之外的原因而获得 NoClassDefFoundError。
Java中的NoClassDefFoundError
定义:
Java 虚拟机无法在运行时找到在编译时可用的特定类。如果一个类在编译时存在,但在运行时在 java 类路径中不可用。
https://i.stack.imgur.com/bDVNo.gif
例子:
该类不在 Classpath 中,没有确切的方法可以知道它,但很多时候你可以看看打印 System.getproperty("java.classpath") ,它会从那里打印你至少可以得到的类路径您的实际运行时类路径的想法。 NoClassDefFoundError 的一个简单示例是类属于缺少的 JAR 文件或 JAR 未添加到类路径中,或者有时 jar 的名称已被某些人更改,例如我的一位同事已将 tibco.jar 更改为 tibco_v3.jar 并且程序是java.lang.NoClassDefFoundError 失败,我想知道出了什么问题。只需尝试使用您认为可以工作的类路径显式运行 -classpath 选项,如果它正在工作,那么这是一个肯定的简短信号,表明有人正在覆盖 java 类路径。 JAR 文件的权限问题也可能导致 Java 中的 NoClassDefFoundError。 XML 配置上的错字也可能导致 Java 中的 NoClassDefFoundError。当您在包中定义的编译类在加载时不存在于同一个包中时,就像在 JApplet 的情况下一样,它将在 Java 中抛出 NoClassDefFoundError。
可能的解决方案:
该类在 Java 类路径中不可用。如果您在 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
我发现,当使用运行时发现的不兼容版本的类编译代码时,有时会出现 NoClassDefFound 错误。我记得的具体实例是 apache 轴库。我的运行时类路径上实际上有 2 个版本,它选择了过期和不兼容的版本,而不是正确的版本,导致 NoClassDefFound 错误。这是在一个命令行应用程序中,我正在使用与此类似的命令。
set classpath=%classpath%;axis.jar
我能够通过使用以下方法获取正确的版本:
set classpath=axis.jar;%classpath%;
这是我目前发现的 best solution。
假设我们有一个名为 org.mypackage
的包,其中包含以下类:
HelloWorld(主类)
支持类
实用程序类
并且定义此包的文件物理存储在目录 D:\myprogram
(在 Windows 上)或 /home/user/myprogram
(在 Linux 上)下。
https://i.stack.imgur.com/XOzAE.png
https://i.stack.imgur.com/cM8gu.png
您可能会看到大量 NoClassDefFoundErrors
的一个有趣案例是:
在类 Example 的静态块中抛出 RuntimeException 拦截它(或者如果它只是在测试用例中抛出无关紧要)尝试创建此类 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
将与静态块 RuntimeException
中的 ExceptionInInitializerError
一起抛出。
当您在 UNIT TESTS 中看到 NoClassDefFoundErrors
时,这一点尤其重要。
在某种程度上,您在测试之间“共享”static
块执行,但最初的 ExceptionInInitializerError
将只在一个测试用例中。第一个使用有问题的 Example
类。其他使用 Example
类的测试用例只会抛出 NoClassDefFoundErrors
。
我将 Spring Framework 与 Maven 一起使用,并在我的项目中解决了这个错误。
类中存在运行时错误。我正在将属性读取为整数,但是当它从属性文件中读取值时,它的值是双倍的。
Spring 没有给我完整的堆栈跟踪运行时在哪一行失败。它只是说NoClassDefFoundError
。但是当我将它作为本机 Java 应用程序执行时(将其从 MVC 中取出),它给出了 ExceptionInInitializerError
,这是真正的原因,也是我跟踪错误的方式。
@xli 的回答让我深入了解了我的代码中可能存在的问题。
NoClassDefFoundError
实际上是由 ExceptionInInitalizerError
引起的,而 ExceptionInInitalizerError
是由 DateTimeParseException
引起的)。这有点误导,不是吗?我知道他们可能有他们这样做的理由,但如果至少有一个小提示,那就太好了,即 NoClassDefFoundError
是另一个异常的结果,无需推断它。再次抛出 ExceptionInInitializerError
会更清楚。有时两者之间的联系可能并不那么明显。
当运行时类加载器加载的类无法访问 java 根加载器已经加载的类时,我得到 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;
}
});
}
}
下面的技术帮助了我很多次:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
其中 TheNoDefFoundClass 是由于偏爱程序使用的同一库的旧版本而可能“丢失”的类。这种情况最常发生在这样的情况下,当客户端软件被部署到一个占主导地位的容器中时,它配备了自己的类加载器和大量最流行的库的古老版本。
如果您有生成代码(EMF 等),则可能有太多静态初始化程序会占用所有堆栈空间。
请参阅 Stack 溢出问题 How to increase the Java stack size?。
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();
每个类都有一个使用 loadClass(String name);
的 ClassLoader
,这就是为什么
explicit class loader uses implicit class loader
NoClassDefFoundError
是 explicit class loader
的一部分。 Error
保证在编译期间该类被呈现,但现在(在运行时)它不存在。
ClassNotFoundException
是 implicit class loader
的一部分。 Exception
在另外可以使用的场景中具有弹性 - 例如反射。
同一项目的两个不同的结帐副本
就我而言,问题在于 Eclipse 无法区分同一项目的两个不同副本。我有一个锁定在主干上(SVN 版本控制),另一个在一个分支中工作。我在工作副本中尝试了一个更改作为 JUnit 测试用例,其中包括将私有内部类提取为自己的公共类,当它工作时,我打开项目的另一个副本以查看其他的需要更改的部分代码。在某些时候,NoClassDefFoundError
突然出现,抱怨私有内部类不存在;双击堆栈跟踪将我带到错误项目副本中的源文件。
关闭项目的主干副本并再次运行测试用例即可解决问题。
我通过禁用所有模块的 preDexLibraries 解决了我的问题:
dexOptions {
preDexLibraries false
...
当我将另一个模块的 Maven 依赖项添加到我的项目时出现此错误,该问题最终通过将 -Xss2m
添加到我的程序的 JVM 选项来解决(自 JDK5.0 以来默认为 1 兆字节)。相信程序没有足够的堆栈来加载类。
当 static 初始化程序尝试加载在运行时不可用的资源包(例如受影响的类尝试从 META-INF
目录加载的属性文件,但不在那里。如果您没有捕获 NoClassDefFoundError
,有时您将无法看到完整的堆栈跟踪;为了克服这个问题,您可以暂时对 Throwable
使用 catch
子句:
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
初始化失败),我将有兴趣查看演示该行为的实际示例(即 MCVE)。
尝试在 Tomcat/JBOSS 服务器上部署应用程序时遇到 NoClassDefFoundError。我使用不同的依赖项来解决问题,但不断收到相同的错误。将所有 javax.* 依赖项标记为 pom.xml 中提供的,并且 war 实际上没有依赖项。问题还是不断出现。
最后意识到 src/main/webapps/WEB-INF/classes 有 classes 文件夹,该文件夹被复制到我的战争中,所以不是编译的类,而是复制这些类,因此没有依赖项更改解决问题。
因此,如果要复制任何以前编译的数据,请小心,删除类文件夹和重新编译后,它起作用了!..
如果有人因为 java.lang.NoClassDefFoundError: org/apache/log4j/Logger
错误而来到这里,在我的情况下,它是因为我使用了 log4j 2(但我没有添加它附带的所有文件)而产生的,并且一些依赖库使用了 log4j 1。解决方案是添加 Log4j 1.x 桥:log4j 2 附带的 jar log4j-1.2-api-<version>.jar
。更多信息请参见 log4j 2 migration。
此错误可能是由未经检查的 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
当我没有在项目的 Java 构建路径的“订购和导出”选项卡上导出类时,出现 NoClassDefFound 错误。确保在添加到项目构建路径的任何依赖项的“订购和导出”选项卡中打勾。请参阅Eclipse warning: XXXXXXXXXXX.jar will not be exported or published. Runtime ClassNotFoundExceptions may result。
也可能是因为您从具有特定包名称的 IDE 复制代码文件,并且您想尝试使用终端运行它。您必须先从代码中删除包名称。这发生在我身上。
就我而言,由于 JDK 版本不匹配,我收到此错误。当我尝试从 Intelij 运行该应用程序时,它无法正常工作,但随后从命令行运行它就可以了。这是因为 Intelij 试图使用已设置的 Java 11 JDK 运行它,但在命令行上它使用 Java 8 JDK 运行。在“文件”>“项目结构”>“项目设置”>“项目 SDK”下切换该设置后,它对我有用。
每个人都在这里谈论一些 Java 配置内容、JVM 问题等,在我的情况下,错误与这些主题完全无关,并且有一个非常简单且易于解决的原因:我的 Controller 的端点有一个错误的注释( 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包等,但这就是我修复错误的方式,如果其他人已经回答了这个问题,我很抱歉,但我无法将其解释为我的问题。
Java 在运行时找不到类 A。 A 类位于来自不同工作区的 Maven 项目 ArtClient 中。所以我将 ArtClient 导入到我的 Eclipse 项目中。我的两个项目使用 ArtClient 作为依赖项。我将库引用更改为这些项目的引用(构建路径-> 配置构建路径)。
问题消失了。
我也遇到了同样的问题,而且我存货了好几个小时。
我找到了解决方案。就我而言,因此定义了静态方法。 JVM 不能创建该类的另一个对象。
例如,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
从 SRC 库中删除两个文件后,我收到了这条消息,当我把它们带回来时,我一直看到这条错误消息。
我的解决方案是:重新启动 Eclipse。从那以后我再也没有看到这条消息:-)
确保这在 module:app
和 module:lib
中匹配:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
和两个 }
)。你能修好它吗?
Error: Could not find or load main class
时,它将被归类为哪一类错误?