为什么我在Java中得到一个NoClassDefFoundError?

我运行我的Java应用程序时遇到NoClassDefFoundError 。 这通常是什么原因?

这是在你的代码依赖的类文件引起的,它在编译时出现,但在运行时没有find。 查找构build时间和运行时类path的差异。

尽pipe这可能是由于编译时和运行时之间的类path不匹配造成的,但这不一定是正确的。

在这种情况下,保持两三个不同的例外是很重要的:

  1. java.lang.ClassNotFoundException这个exception表示在类path中找不到这个类。 这表明我们正在尝试加载类定义,而类在类path中不存在。

  2. java.lang.NoClassDefFoundError该exception表示JVM在其内部类定义数据结构中查找类的定义,但没有find它。 这不同于说它不能从类path加载。 通常这表明我们以前试图从classpath中加载一个类,但是由于某种原因它失败了 – 现在我们试图再次使用这个类(因此需要加载它,因为它上次失败了)甚至不会尝试加载它,因为我们没有加载它(并有理由怀疑我们会再次失败)。 早期的失败可能是一个ClassNotFoundException或一个ExceptionInInitializerError(表示静态初始化块失败)或任何其他问题。 重点是NoClassDefFoundError不一定是类path问题。

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

我发现,有时我得到一个NoClassDefFound错误时编译与运行时发现类的不兼容版本的代码。 我记得的具体实例是与Apache轴库。 在我的运行时类path中实际上有两个版本,它是拾取过时和不兼容的版本,而不是正确的,导致NoClassDefFound错误。 这是在一个命令行应用程序,我正在使用类似的命令。

 set classpath=%classpath%;axis.jar 

我能够通过使用以下代码来获取正确的版本:

 set classpath=axis.jar;%classpath%; 

NoClassDefFoundError在Java中

定义:

  1. Java虚拟机无法在运行时find在编译时可用的特定类。

  2. 如果一个类在编译期间出现,但在运行时在java classpath中不可用。

在这里输入图像描述

例子:

  1. 这个类不在Classpath中,没有办法知道它,但很多时候你可以看看打印System.getproperty(“java.classpath”),它将打印从那里你可以至less得到类path您的实际运行时类path的一个想法。
  2. NoClassDefFoundError的一个简单例子是class属于一个缺less的JAR文件,或者JAR没有被添加到classpath中,或者有时候jar的名字已经被某个人改变了,我的一个同事已经把tibco.jar改成了tibco_v3.jar,程序是与java.lang.NoClassDefFoundError失败,我想知道什么是错的。

  3. 只要尝试使用显式的-classpath选项来运行你认为可以工作的类path,如果它正在工作,那么肯定会有人重写java classpath。

  4. JAR文件上的权限问题也会导致Java中的NoClassDefFoundError。
  5. 在XMLconfiguration上的错字也会导致Java中的NoClassDefFoundError。
  6. 当你在一个包中定义的编译类在加载时不会出现在同一个包中,就像在JApplet的情况下一样,它会抛出Java中的NoClassDefFoundError。

可能的解决scheme:

  1. 该类在Java Classpath中不可用。
  2. 如果你在J2EE环境下工作的可见性比Class中的多个Classloader还可能导致java.lang.NoClassDefFoundError,请参阅示例和场景部分进行详细讨论。
  3. 检查日志文件中的java.lang.ExceptionInInitializerError。 由于静态初始化失败而导致的NoClassDefFoundError非常普遍。
  4. 因为NoClassDefFoundError是java.lang.LinkageError的一个子类,所以如果像本地库这样的依赖项之一可能不可用的话,它也会出现。
  5. 任何启动脚本都将重写Classpath环境variables。
  6. 您可能正在使用jar命令运行您的程序,并且未在清单文件的ClassPath属性中定义类。

资源:

解决NoClassDefFoundError的3种方法

java.lang.NoClassDefFoundError问题模式

我正在用maven使用spring框架,并在我的项目中解决了这个错误。

class上有一个运行时错误。 我正在阅读一个整数属性,但是当它从属性文件中读取值时,它的值是双倍的。 Spring没有给我一个完整的堆栈跟踪运行时失败的行。 它只是说NoClassDefFoundError 。 但是,当我作为一个本地Java应用程序(从MVC中取出)执行它时,它给了ExceptionInInitializerError这是真正的原因,这是我如何追溯错误。

@ xli的回答让我深入了解了我的代码中可能出现的错误。

当由运行时类加载器加载的类不能访问java根加载器已经加载的类时,我得到NoClassFoundError。 因为不同的类加载器处于不同的安全域(根据java),所以jvm将不允许已经由根加载器加载的类在运行时加载器地址空间中被parsing。

用'java -javaagent:tracer.jar [你的JAVA ARGS]'运行你的程序

它产生显示加载类的输出,以及加载该类的加载器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; } }); } } 

这是迄今为止我find的最好的解决scheme 。

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

  • HelloWorld(主类)
  • SupportClass
  • UtilClass

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

文件结构如下所示: 在这里输入图像描述

当我们调用Java时,我们指定要运行的应用程序的名称: org.mypackage.HelloWorld 。 但是,我们还必须告诉Java在哪里查找定义我们包的文件和目录。 所以要启动程序,我们必须使用下面的命令: 在这里输入图像描述

下面的技术帮了我很多次:

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

TheNoDefFoundClass是由于您的程序使用的相同库的旧版本的偏好而可能“丢失”的类。 这种情况最常见的情况是,当客户端软件被部署到一个占统治地位的容器中时,他们拥有自己的类加载器和大量最受欢迎的库的古代版本。

如果你有生成代码(EMF等),可能会有太多的静态初始化器消耗所有的堆栈空间。 如何增加Java堆栈大小? 。

我有一个同样的问题,我是股票长时间。 我find了解决scheme,在我的情况下,有定义的静态方法,因为JVM不能创build该类的另一个对象。 例如,私人静态HttpHost代理=新的HttpHost(proxyHost,Integer.valueOf(proxyPort),“http”);

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

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

在我的情况下,问题是Eclipse无法区分同一个项目的两个不同副本。 我有一个locking在中继(SVN版本控制),另一个在一个分支一次工作。 我在工作副本上做了一个更改,作为一个JUnittesting用例,其中包括提取一个私有的内部类作为一个公共类,当它工作时,我打开另一个项目副本来环顾其他一些部分需要改变的代码。 在某个时候,出现了NoClassDefFoundError ,抱怨私人的内部类不在那儿; 双击堆栈跟踪将我带到错误的项目副本中的源文件。

closures项目的主干副本并再次运行testing用例摆脱了这个问题。

确保这个模块匹配:应用程序和模块:lib

  android { compileSdkVersion 23 buildToolsVersion '22.0.1' packagingOptions { } defaultConfig { minSdkVersion 17 targetSdkVersion 23 versionCode 11 versionName "2.1" } 

从SRC库中删除2个文件后,我得到了这个消息,当我把它们带回来,我不断看到这个错误消息。 我的解决scheme是:重新启动Eclipse。 从那以后,我再也没有看到这个消息:-)