NoClassDefFoundError和ClassNotFoundException的原因和区别是什么?

NoClassDefFoundErrorClassNotFoundException之间的区别是什么?

是什么导致它们被抛出?如何解决这些问题?

在修改现有代码以包含新的jar文件时,我经常遇到这些throwables。 对于一个通过webstart分发的java应用程序,我已经在客户端和服务器端击中了它们

我发现的可能原因是:

  1. 未包含在build.xml中用于代码客户端的包
  2. 我们正在使用的新jar缺少运行时类路径
  3. 版本与上一个jar冲突

当我今天遇到这些问题时,我采取了一种反复尝试的方法来让事情正常运行。我需要更多的清晰和理解。

188187 次浏览

NoClassDefFoundError基本上是一个链接错误。当您尝试实例化一个对象(静态地使用“new”),并且在编译期间没有找到它时,就会发生这种情况。

ClassNotFoundException更通用,当你试图使用一个不存在的类时,它是一个运行时异常。例如,你在函数中有一个参数接受一个接口,有人传入一个实现该接口的类,但你没有访问该类的权限。它还涵盖了动态类加载的情况,例如使用loadClass()Class.forName()

与Java API规范的区别如下。

ClassNotFoundException:

当应用程序试图 通过类的字符串加载类 使用名称:< / p >

  • Class中的forName方法。
  • ClassLoader中的findSystemClass方法。
  • ClassLoader中的loadClass方法。

但没有类的定义

.

.

NoClassDefFoundError:

如果Java虚拟机或 ClassLoader实例尝试加载 在类的定义中(作为部分) 的正常方法调用或作为的一部分 方法创建一个新实例 表达式)和没有定义的

搜索类定义 当前执行时已存在 类被编译,但是定义

因此,当源代码成功编译时出现NoClassDefFoundError,但在运行时,没有找到所需的class文件。这可能会发生在JAR文件的分发或生产中,其中不包括所有必需的class文件。

至于ClassNotFoundException,它似乎源于试图在运行时对类进行反射调用,但程序试图调用的类并不存在。

两者之间的区别是一个是Error,另一个是Exception。With NoClassDefFoundError是一个Error,它源于Java虚拟机在查找期望查找的类时遇到问题。预期在编译时工作的程序不能运行,因为没有找到class文件,或者与在编译时生成或遇到的文件不相同。这是一个非常严重的错误,因为该程序不能由JVM启动。

另一方面,ClassNotFoundException是一个Exception,所以它在某种程度上是预期的,并且是可以恢复的。使用反射是很容易出错的(因为有一些预期,事情可能不会像预期的那样进行。没有编译时检查来查看所有必需的类是否存在,因此任何查找所需类的问题都会在运行时出现。

当试图通过String引用该类来加载该类时,会抛出ClassNotFoundException。例如,Class.forName()中的参数to是一个字符串,这可能会将无效的二进制名称传递给类加载器。

当遇到可能无效的二进制名称时抛出ClassNotFoundException;例如,如果类名有'/'字符,你一定会得到一个ClassNotFoundException。当直接引用的类在类路径上不可用时,它也会被抛出。

另一方面,NoClassDefFoundError被抛出

  • 当类的实际物理表示- .class文件不可用时,
  • 或者类已经在不同的类加载器中加载了(通常是父类加载器已经加载了该类,因此该类不能再次加载),
  • 或者如果发现了不兼容的类定义——类文件中的名称与请求的名称不匹配,
  • 或者(最重要的是)如果无法定位和加载依赖类。在这种情况下,可能已经定位并加载了直接引用的类,但依赖类不可用或无法加载。在这种情况下,直接引用的类可以通过class加载。forName或等效方法。这表明链接失败。

简而言之,当类加载器无法找到或加载类定义时,通常会在new()语句或加载先前不存在的类的方法调用上抛出NoClassDefFoundError(与ClassNotFoundException基于字符串的类加载相反)。

最终,当ClassLoader无法加载类时,由ClassLoader实现抛出ClassNotFoundException实例。大多数自定义类加载器实现执行此操作,因为它们扩展了URLClassLoader。通常类加载器不会在任何方法实现上显式抛出NoClassDefFoundError——这个异常通常是由HotSpot编译器中的JVM抛出的,而不是由类加载器本身抛出的。

当ClassLoader没有找到所报告的类时,将抛出ClassNotFoundException。这通常意味着类从CLASSPATH中缺失。这也可能意味着这个类正试图从父类加载器中加载的另一个类中加载,因此子类加载器中的类是不可见的。在应用程序服务器等更复杂的环境中工作时,有时会出现这种情况(WebSphere因此类类加载器问题而臭名昭著)。

人们经常容易混淆java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException,但是有一个重要的区别。例如,像这样的异常(实际上是一个错误,因为java.lang.NoClassDefFoundError是java.lang.Error的子类)

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

并不意味着ActiveMQConnectionFactory类不在CLASSPATH中。事实上恰恰相反。这意味着类ActiveMQConnectionFactory是由ClassLoader找到的,但是在尝试加载类时,它在读取类定义时遇到了错误。这通常发生在有问题的类有静态块或成员使用ClassLoader没有找到的class时。因此,要找到罪魁祸首,请查看相关类的源代码(在本例中为ActiveMQConnectionFactory),并查找使用静态块或静态成员的代码。如果您没有访问源代码的权限,那么只需使用JAD反编译即可。

在检查代码时,假设你发现如下一行代码,确保类SomeClass在CLASSPATH中。

private static SomeClass foo = new SomeClass();

提示:要找出一个类属于哪个jar,您可以使用网站jarFinder。这允许您使用通配符指定类名,并在其jar数据库中搜索该类。Jarhoo允许你做同样的事情,但它不再免费使用。

如果你想在本地路径中定位一个类属于哪个jar,你可以使用像jarscan (http://www.inetfeedback.com/jarscan/)这样的实用程序。您只需指定您想要定位的类以及您希望它开始在jar和zip文件中搜索类的根目录路径。

NoClassDefFoundError (NCDFE)发生在代码运行“new Y()”并且无法找到Y类时。

可能只是像其他注释所建议的那样,从类加载器中缺少Y,但也可能是Y类没有签名或具有无效的签名,或者Y是由对代码不可见的其他类加载器加载的,甚至Y依赖于由于上述任何原因而无法加载的Z。

如果发生这种情况,那么JVM将记住加载X的结果(NCDFE),并且每次你请求Y时它都会抛出一个新的NCDFE,而不告诉你为什么:

class a {
static class b {}
public static void main(String args[]) {
System.out.println("First attempt new b():");
try {new b(); } catch(Throwable t) {t.printStackTrace();}
System.out.println("\nSecond attempt new b():");
try {new b(); } catch(Throwable t) {t.printStackTrace();}
}
}

将其保存为a.java文件

代码只是尝试实例化一个新的“b”类两次,除此之外,它没有任何错误,也没有做任何事情。

使用javac a.java编译代码,然后通过调用java -cp . a运行a——它应该只打印出两行文本,并且应该正常运行,没有错误。

然后删除“a$b.class”文件(或用垃圾填充它,或在上面复制a.class)以模拟缺失或损坏的类。事情是这样的:

First attempt new b():
java.lang.NoClassDefFoundError: a$b
at a.main(a.java:5)
Caused by: java.lang.ClassNotFoundException: a$b
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
... 1 more


Second attempt new b():
java.lang.NoClassDefFoundError: a$b
at a.main(a.java:7)

第一次调用会导致ClassNotFoundException(类装入器在找不到类时抛出),它必须包装在未检查的NoClassDefFoundError中,因为所讨论的代码(new b())应该正常工作。

第二次尝试当然也会失败,但正如您所看到的,包装的异常不再存在,因为ClassLoader似乎记住了失败的类装入器。你只看到了非传染性疾病,完全不知道到底发生了什么。

因此,如果您看到没有根本原因的nccdfe,您需要查看是否可以追溯到类第一次加载时,以查找错误的原因。

获得这些错误的原因是什么,以及如何处理这些错误的思想过程?

它们是密切相关的。当Java按名称查找特定类且无法成功加载时抛出ClassNotFoundException。当Java去寻找一个链接到一些现有代码的类,但由于这样或那样的原因(例如,错误的类路径,错误的Java版本,错误的库版本)无法找到它时,会抛出NoClassDefFoundError,这是完全致命的,因为它表明某些事情发生了严重错误。

如果你有C语言背景,CNFE就像dlopen()/dlsym()的失败,而NCDFE是链接器的问题;在第二种情况下,相关的类文件不应该在您试图使用它们的配置中实际编译过。

在实践中添加一个可能的原因:

  • ClassNotFoundException:正如cletus所说,当接口的继承类不在类路径中时使用接口。例如,服务提供者模式(或服务定位器)试图定位一些不存在的类
  • NoClassDefFoundError:找到了给定的类,但没有找到给定类的依赖项

在实践中,< em > < / em >错误可能会被抛出默默地< em > < / em >,例如,你提交了一个计时器任务,在计时器任务中它会抛出< em > < / em >错误,而在大多数情况下,你的程序只捕获< em > < / em >异常。然后< / em > < em >计时器主循环结束,没有任何信息。与NoClassDefFoundError类似的错误是ExceptionInInitializerError,当您的静态初始化器或静态变量的初始化器抛出异常时。

http://www.javaroots.com/2013/02/classnotfoundexception-vs.html:

ClassNotFoundException:当类装入器无法在类路径中找到所需的类时发生。因此,基本上您应该检查类路径并在类路径中添加类。

NoClassDefFoundError:这是更难调试和找到原因。当在编译时存在所需的类,但在运行时类被更改或删除,或者类的静态初始化抛出的异常时,将引发此异常。这意味着要加载的类存在于类路径中,但该类所需的类之一要么被删除,要么被编译器加载失败。你应该看到依赖于这个类的类。

例子:

public class Test1
{
}




public class Test
{
public static void main(String[] args)
{
Test1 = new Test1();
}


}

现在,在编译完这两个类之后,如果删除Test1.class文件并运行Test类,它将抛出

Exception in thread "main" java.lang.NoClassDefFoundError: Test
at Test1.main(Test1.java:5)
Caused by: java.lang.ClassNotFoundException: Test
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more

ClassNotFoundException:当应用程序试图通过类的名称装入类,但无法找到具有指定名称的类的定义时抛出。

NoClassDefFoundError:如果Java虚拟机试图装入类的定义,但找不到该类的定义,则抛出。

例# 1:

class A{
void met(){
Class.forName("com.example.Class1");
}
}

如果com/example/Class1不存在于任何类路径中,则抛出ClassNotFoundException

例# 2:

Class B{
void met(){
com.example.Class2 c = new com.example.Class2();
}
}

如果编译B时存在com/example/Class2,但在执行时没有找到,则抛出NoClassDefFoundError

两者都是运行时异常。

给定类装入器sussystem动作:

http://www.artima.com/insidejvm/ed2/images/fig7-1.gif

这是一篇帮助我理解差异的文章:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

如果在类加载期间发生错误,则a的实例 LinkageError的子类必须在程序中的某个点抛出

.(直接或间接)使用正在加载的类或接口

如果Java虚拟机试图加载类C 验证(§5.4.1)或解决(§5.4.3)(但不包括初始化 (§5.5)),以及类装入器,用于初始化C 抛出ClassNotFoundException的实例,然后是Java Virtual 机器必须抛出NoClassDefFoundError的实例,其原因为 ClassNotFoundException的实例

因此,ClassNotFoundExceptionNoClassDefFoundError的根本原因 NoClassDefFoundError是类型加载错误的特殊情况,发生在链接步骤

通过名称本身,我们可以很容易地识别出一个来自Exception,另一个来自Error

例外:在程序执行期间发生异常。程序员可以通过try catch块处理这些异常。我们有两种类型的异常。在编译时抛出的已检查异常。在运行时抛出的运行时异常,这些异常通常是由于糟糕的编程而发生的。

这些根本不是例外,它超出了程序员的范围。这些错误通常由JVM抛出。


enter image description here 图片来源 < / p >

的区别:

ClassNotFoundException:

  • 类装入器无法验证 链接中的字节代码。
  • ClassNotFoundException是一个检查异常,当应用程序试图通过类的全限定名加载类,但在类路径上找不到类的定义时发生。
  • 当使用ClassLoader.loadClass()、class . forname()和ClassLoader.findSystemClass()在运行时提供类名时,涉及到类的显式加载,就会出现ClassNotFoundException

NoClassDefFoundError:

  • 类装入器对链接中的类的解决引用失败。
  • NoClassDefFoundError是一个派生自LinkageError类的错误,这是一个致命错误。当JVM试图使用new关键字实例化一个类或使用方法调用加载一个类时,无法找到类的定义,就会发生这种情况。
  • NoClassDefFoundError是类的隐式加载的结果,因为来自该类的方法调用或任何变量访问。

相似之处:

  • NoClassDefFoundErrorClassNotFoundException都与类在运行时不可用有关。
  • ClassNotFoundExceptionNoClassDefFoundError都与Java类路径相关。

ClassNotFoundException和NoClassDefFoundError的区别

enter image description here

当我需要复习的时候,我会一遍又一遍地提醒自己

ClassNotFoundException

类层次结构

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

在调试

  1. Required jar,类路径中缺少类。
  2. 验证所有必需的jar都在jvm的类路径中。

NoClassDefFoundError

类层次结构

NoClassDefFoundError extends LinkageError  extends Error extends Throwable

在调试

  1. 动态加载一个编译正确的类的问题
  2. 静态块、构造函数、依赖类的init()方法的问题,实际错误被多层包装[特别是当你使用spring、hibernate时,实际异常被包装,你将得到NoClassDefError]
  3. 当你面对依赖类的静态块下的“ClassNotFoundException”时
  4. 类的版本问题。 当你在不同的jar/packages下有两个相同类的v1和v2版本时,就会发生这种情况,它是用v1和v2成功编译的,在运行时加载,而运行时没有相关的方法/vars&您将看到这个异常。[我曾经通过在类路径中出现的多个jar下删除log4j相关类的副本来解决这个问题]

ClassNotFoundException是一个检查异常,当我们告诉JVM使用class . forname()或ClassLoader.findSystemClass()或ClassLoader.loadClass()方法根据类的字符串名加载类,并且在类路径中没有找到所提到的类时,会发生该异常。

大多数情况下,当您试图运行应用程序而不使用所需的JAR文件更新类路径时,会发生此异常。例如,你可能已经看到这个异常时,做JDBC代码连接到你的数据库,即mysql,但你的类路径没有JAR。

NoClassDefFoundError发生错误当JVM试图加载一个特定的类的代码执行(作为一个正常的一部分方法调用或使用新的关键字创建一个实例的一部分),这类在类路径中不存在,但在编译时,因为为了执行程序需要编译它,如果你正在使用一个类不存在编译器会提高编译错误。

下面是简短的描述

enter image description here

你可以阅读关于ClassNotFoundException Vs NoClassDefFoundError的一切获取更多细节。

ClassNotFoundException和NoClassDefFoundError发生在运行时没有找到特定的类时。然而,它们发生在不同的场景中。

ClassNotFoundException是一个异常,当您试图在运行时使用class . forname()或loadClass()方法加载一个类,并且在类路径中没有找到所提到的类时发生。

    public class MainClass
{
public static void main(String[] args)
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
}catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}






java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError是当特定类在编译时存在,但在运行时不存在时发生的错误。

    class A
{
// some code
}
public class B
{
public static void main(String[] args)
{
A a = new A();
}
}

编译上述程序时,将生成两个.class文件。一个是a类,另一个是b类。如果你删除A.class文件并运行B.class文件,Java运行时系统将抛出NoClassDefFoundError,如下所示:

    Exception in thread "main" java.lang.NoClassDefFoundError: A
at MainClass.main(MainClass.java:10)
Caused by: java.lang.ClassNotFoundException: A
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)