当我运行我的Java应用程序时,我得到一个NoClassDefFoundError
。 这通常是什么原因造成的?
虽然这有可能是由于编译时和运行时的classpath不匹配造成的,但这不一定是真的。
在这种情况下,在我们的头脑中保持两个或三个不同的例外情况是很重要的。
java.lang.ClassNotFoundException
这个异常表示在classpath上没有找到这个类。 这表明我们试图加载类的定义,而该类在classpath上不存在。
2.java.lang.NoClassDefFoundError
这个异常表示JVM在其内部的类定义数据结构中寻找一个类的定义,但没有找到它。 这与说它不能从classpath中加载不同。 通常这表明我们以前曾试图从classpath中加载一个类,但由于某种原因而失败了--现在我们试图再次使用这个类(因此需要加载它,因为它上次失败了),但我们甚至不打算尝试加载它,因为我们之前加载它失败了(而且有理由怀疑我们会再次失败)。 先前的失败可能是ClassNotFoundException或ExceptionInitializerError(表示静态初始化块中的失败)或任何其他问题。 重点是,NoClassDefFoundError不一定是classpath问题。
下面是说明java.lang.NoClassDefFoundError
的代码。
详细说明请看[Jared'的回答][1]。
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;
}
*Java中没有ClassDefFoundError。
****定义:**
Java虚拟机在运行时找不到在编译时可用的某个类。
如果一个类在编译时存在,但在运行时java classpath中不可用。
[![在此输入图像描述][1]][1] 。
实例:。
该类不在Classpath中,没有确定的方法知道它,但很多时候你可以看看print System.getproperty("java.classpath"),它就会打印出classpath,从那里你至少可以了解你的实际运行时classpath。
一个简单的NoClassDefFoundError的例子是类属于一个缺失的JAR文件,或者JAR没有被添加到classpath中,或者有时jar'的名字被某人改变了,就像在我的例子中,我的一个同事把tibco.jar改成了tibco_v3.jar,程序以java.lang.NoClassDefFoundError失败,我想知道什么'的问题。
试着用显式-classpath选项运行,用你认为能用的classpath,如果它'工作了,那么它'就是一个肯定的短信号,有人在覆盖java classpath。
JAR文件的权限问题也会导致Java中的NoClassDefFoundError。
5.XML配置上的打字错误也会导致Java中的NoClassDefFoundError。
当你的编译类定义在一个包中,但在加载时没有出现在同一个包中,就像JApplet的情况一样,它将在Java中抛出NoClassDefFoundError。
可能的解决方案:
2.如果你是在J2EE环境中工作,那么在多个Classloader中类的可见性也会导致java.lang.NoClassDefFoundError,详细的讨论请看例子和场景部分。
检查日志文件中是否有java.lang.ExceptionInInitializerError。 静态初始化失败导致的NoClassDefFoundError相当常见。
因为NoClassDefFoundError是java.lang.LinkageError的一个子类,所以如果它的一个依赖关系(如native library)不可用,也会出现NoClassDefFoundError。
任何启动脚本都会覆盖Classpath环境变量。
资源:【3种解决NoClass的方法
解决NoClassDefFoundError的3种方法][2] 。
[java.lang.NoClassDefFoundError问题模式][3]
[1]: http://i.stack.imgur.com/bDVNo.gif [2]: https://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html [3]: [3]:http://javaeesupportpatterns.blogspot.in/2011/08/javalangnoclassdeffounderror-problem.html
我发现,有时我得到一个NoClassDefFound的错误,当代码被编译时,在运行时发现的类的不兼容版本。 我记得具体的例子是关于apache axis库的。 实际上,在我的运行时classpath上有两个版本,它接收的是过时的、不兼容的版本,而不是正确的版本,导致NoClassDefFound错误。 这是在一个命令行应用程序中,我使用了一个与此类似的命令。
set classpath=%classpath%;axis.jar
我通过使用以下方法使其获得了正确的版本。
set classpath=axis.jar;%classpath%;
这是我目前找到的【最佳解决方案】[1]。
假设我们有一个名为 "org.mypackage "的包,其中包含以下类。
和定义这个包的文件实际存储在D:\myprogram
(在Windows上)或/home/user/myprogram
(在Linux上)目录下。
文件结构看起来像这样。 [![在此输入图像描述][2]][2] 。
当我们调用Java时,我们指定要运行的应用程序的名称。
org.mypackage.HelloWorld
.
然而,我们还必须告诉Java在哪里寻找定义我们包的文件和目录。
所以要启动程序,我们必须使用下面的命令。
[! [在这里输入图像描述][3]][3]
[1]: https://en.wikipedia.org/wiki/Classpath_%28Java%29#Setting_the_path_to_execute_Java_programs [2]: http://i.stack.imgur.com/XOzAE.png [3]: http://i.stack.imgur.com/cM8gu.png
我在使用[Spring Framework][1]和[Maven][2]时,解决了我项目中的这个错误。
类中出现了一个运行时错误。 我把一个属性读为整数,但当它从属性文件中读取值时,它的值是双数。
Spring没有给我一个完整的堆栈跟踪,说明运行时在哪一行失败。
它只是说NoClassDefFoundError
。
但是当我把它作为一个本地Java应用程序执行时(把它从MVC中取出来),它给出了ExceptionInInitializerError
,这才是真正的原因,这也是我追踪错误的原因。
@xli'的回答让我明白了我的代码中可能存在的问题。
[1]: http://en.wikipedia.org/wiki/Spring_Framework [2]: http://en.wikipedia.org/wiki/Apache_Maven
当运行时类加载器加载的类不能访问已经由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;
}
});
}
}
有一个有趣的情况是,当你看到很多 "NoClassDefFoundErrors "的时候,你会发现
Example
的static
块中抛出
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
中的ExceptionInitializerError
被抛出。
当你在你的UNIT TESTS中看到NoClassDefFoundErrors
时,这种情况尤其重要。
在某种程度上,你在"共享"
在测试之间执行static
块,但初始的ExceptionInInitializerError
将只是在一个测试用例中。
第一个使用有问题的Example
类的测试用例。
其他使用Example
类的测试用例只会抛出NoClassDefFoundErrors
。
如果你有生成代码(EMF等),可能会有太多的静态初始化器,会消耗所有的栈空间。
参见Stack Overflow问题https://stackoverflow.com/questions/3700459/how-to-increase-the-java-stack-size。
NoClassDefFoundError
也可能发生在static初始化器试图加载一个在运行时不可用的资源束时,例如受影响的类试图从META-INF
目录中加载一个属性文件,但不在那里。
如果你没有捕捉到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);
}
如果有人因为java.lang.NoClassDefFoundError: org/apache/log4j/Logger
错误,在我的例子中,它的产生是因为我使用了log4j 2(但我没有添加所有附带的文件),而一些依赖库使用了log4j 1。
解决的办法是添加log4j 1.x桥。
jar log4j-1.2-api-<version>.jar
,它是和log4j 2一起的。
更多信息请参见log4j 2 [migration][1]。
[1]: https://logging.apache.org/log4j/2.x/manual/migration.html
在我的案例中,问题是Eclipse'无法区分同一项目的两个不同副本。
我有一个锁定在 trunk 上(SVN 版本控制),另一个则在一个分支中工作。
我试着在工作副本中做了一个改动,作为JUnit测试用例,其中包括提取一个私有的内部类成为自己的公有类,当它在工作时,我打开项目的另一个副本,查看需要改动的代码的其他部分。
不知什么时候,弹出了NoClassDefFoundError
,抱怨私有内类不存在。
在堆栈跟踪中双击,我来到了错误项目副本中的源文件。
关闭项目的主干副本,再次运行测试用例,问题就解决了。
这个错误可能是由于未勾选Java版本要求造成的。
在我的例子中,我在构建一个高知名度的开源项目时,通过使用SDKMAN!从Java 9切换到Java 8,就能解决这个错误。
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
然后按照下面的方法做一个干净的安装。
当使用Maven作为你的构建工具时,有时做一个*干净的'install'.build 在禁用测试的情况下是很有帮助的,而且通常令人欣慰。 在禁用测试的情况下进行**构建,有时会很有帮助--而且通常会很满意。
mvn clean install -DskipTests
现在所有的东西都已经完成了构建和安装,你可以继续运行测试了。
mvn test
当我没有在"Order and Export".标签上导出一个类时,我得到了NoClassDefFound错误。 选项卡上导出一个类。 确保在"Order and Export" 选项卡中打上复选标记,您可以将任何依赖项添加到项目的构建路径中。 参见https://stackoverflow.com/questions/8884818/eclipse-warning-xxxxxxxxxxx-jar-will-not-be-exported-or-published-runtime-clas。