NoClassDefFoundError
当我运行我的 Java 应用程序时,我得到了一个。这通常是什么原因?
30 回答
虽然这可能是由于编译时和运行时之间的类路径不匹配,但这不一定是真的。
在这种情况下,将两个或三个不同的例外直接放在我们的脑海中是很重要的:
java.lang.ClassNotFoundException
此异常表明在类路径中找不到该类。这表明我们正在尝试加载类定义,并且类路径中不存在该类。java.lang.NoClassDefFoundError
此异常表明 JVM 在其内部类定义数据结构中查找类的定义,但没有找到。这与说它无法从类路径加载不同。通常这表明我们之前尝试从类路径加载一个类,但由于某种原因它失败了 - 现在我们试图再次使用该类(因此需要加载它,因为它上次失败了),但是我们'甚至不会尝试加载它,因为我们之前未能加载它(并且有理由怀疑我们会再次失败)。较早的失败可能是 ClassNotFoundException 或 ExceptionInInitializerError(指示静态初始化块中的失败)或任何数量的其他问题。关键是,NoClassDefFoundError 不一定是类路径问题。
当您的代码依赖于一个类文件并且它在编译时存在但在运行时找不到时会导致这种情况。寻找构建时间和运行时类路径的差异。
这是说明的代码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();
}
}
简单计算器.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
Java中的NoClassDefFoundError
定义:
Java 虚拟机无法在运行时找到在编译时可用的特定类。
如果一个类在编译时存在,但在运行时在 java 类路径中不可用。
例子:
- 该类不在 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 属性中未定义类。
资源:
我发现,当使用运行时发现的不兼容版本的类编译代码时,有时会出现 NoClassDefFound 错误。我记得的具体实例是 apache 轴库。在我的运行时类路径中实际上有 2 个版本,它选择了过期和不兼容的版本,而不是正确的版本,导致 NoClassDefFound 错误。这是在一个命令行应用程序中,我正在使用与此类似的命令。
set classpath=%classpath%;axis.jar
我能够通过使用以下方法获取正确的版本:
set classpath=axis.jar;%classpath%;
这是迄今为止我找到的最好的解决方案。
假设我们有一个名为org.mypackage
包含类的包:
- HelloWorld(主类)
- 支持类
- 实用程序类
并且定义此包的文件物理存储在目录下D:\myprogram
(在 Windows 上)或/home/user/myprogram
(在 Linux 上)。
当我们调用 Java 时,我们指定要运行的应用程序的名称:org.mypackage.HelloWorld
. 然而,我们还必须告诉 Java 在哪里寻找定义我们包的文件和目录。因此,要启动程序,我们必须使用以下命令:
您可能会看到很多有趣的案例NoClassDefFoundErrors
是:
throw
一个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
。
当您NoClassDefFoundErrors
在UNIT TESTS中看到时,这尤其重要。
在某种程度上,您static
在测试之间“共享”块执行,但初始ExceptionInInitializerError
将仅在一个测试用例中。第一个使用有问题的Example
类。其他使用该类的测试用例Example
只会抛出NoClassDefFoundErrors
.
我在Maven中使用Spring Framework并在我的项目中解决了这个错误。
类中存在运行时错误。我正在将属性读取为整数,但是当它从属性文件中读取值时,它的值是双倍的。
Spring 没有给我完整的堆栈跟踪运行时在哪一行失败。它简单地说NoClassDefFoundError
。但是当我将它作为本机 Java 应用程序执行时(将其从 MVC 中取出),它给出ExceptionInInitializerError
了真正的原因以及我如何跟踪错误。
@xli 的回答让我深入了解了我的代码中可能存在的问题。
当运行时类加载器加载的类无法访问 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 等),则可能有太多静态初始化程序会占用所有堆栈空间。
请参阅堆栈溢出问题如何增加 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();
每个类都有一个ClassLoader
which usesloadClass(String name);
这就是为什么
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
...
NoClassDefFoundError
当静态初始化程序尝试加载在运行时不可用的资源包时也会发生,例如受影响的类尝试从META-INF
目录加载但不存在的属性文件。如果你不 catch 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);
}
当我将另一个模块的 Maven 依赖项添加到我的项目时出现此错误,最终通过添加-Xss2m
到我的程序的 JVM 选项解决了这个问题(自 JDK5.0 以来默认为 1 兆字节)。相信程序没有足够的堆栈来加载类。
尝试在 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-1.2-api-<version>.jar
log4j 2 附带的 jar。更多信息在 log4j 2迁移中。
此错误可能是由未经检查的Java 版本要求引起的。
就我而言,我能够在构建一个备受瞩目的开源项目时解决此错误,方法是使用SDKMAN 从 Java 9 切换到 Java 8!.
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
然后如下所述进行全新安装。
当使用Maven作为你的构建工具时,有时会很有帮助——而且通常是令人满意的,在test disabled的情况下进行干净的“安装”构建。
mvn clean install -DskipTests
现在一切都已构建和安装,您可以继续运行测试。
mvn test
当我没有在项目的 Java 构建路径中的“订购和导出”选项卡上导出类时,出现 NoClassDefFound 错误。确保在添加到项目构建路径的任何依赖项的“订购和导出”选项卡中打勾。请参阅Eclipse 警告:XXXXXXXXXXX.jar 将不会被导出或发布。运行时 ClassNotFoundExceptions 可能会导致。
也可能是因为您从具有特定包名称的 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包等,但这就是我修复错误的方式,如果其他人已经回答了这个问题,我很抱歉,但我无法将其解释为我的问题。
我也遇到了同样的问题,而且我存货了好几个小时。
我找到了解决方案。就我而言,因此定义了静态方法。JVM 不能创建该类的另一个对象。
例如,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
Java 在运行时找不到类 A。A 类位于来自不同工作区的 Maven 项目 ArtClient 中。所以我将 ArtClient 导入到我的 Eclipse 项目中。我的两个项目使用 ArtClient 作为依赖项。我将库引用更改为这些项目的引用(构建路径-> 配置构建路径)。
问题消失了。
从 SRC 库中删除两个文件后,我收到了这条消息,当我把它们带回来时,我一直看到这条错误消息。
我的解决方案是:重新启动 Eclipse。从那以后我再也没有看到这条消息:-)
确保这与module:app
and匹配module:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}