NoClassDefFoundError和ClassNotFoundException之间的区别是什么?

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

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

我发现的可能原因是:

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

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


当前回答

通过名称本身,我们可以很容易地识别一个来自异常,另一个来自错误。

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

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


图片来源

的区别:

ClassNotFoundException:

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

NoClassDefFoundError:

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


相似之处:

NoClassDefFoundError和ClassNotFoundException都与类在运行时不可用有关。 ClassNotFoundException和NoClassDefFoundError都与Java类路径相关。

其他回答

从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虚拟机试图装入类的定义,但找不到该类的定义时抛出。

ClassNotFoundException和NoClassDefFoundError的区别

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 API规范的区别如下。

ClassNotFoundException:

当应用程序尝试时抛出 通过类的字符串加载类 名称使用: 类class中的forName方法。 类ClassLoader中的findSystemClass方法。 类ClassLoader中的loadClass方法。 但是没有类的定义 可以找到指定的名称。

NoClassDefFoundError:

抛出如果Java虚拟机或 ClassLoader实例尝试加载 在类的定义中(作为部分) 的正常方法调用或作为的一部分 方法创建一个新实例 表达式)和没有定义的 可以找到类。 搜索的类定义 当前执行时已存在 类被编译,但是定义 再也找不到。

因此,当源代码成功编译时,NoClassDefFoundError似乎发生了,但在运行时,没有找到所需的类文件。这可能发生在JAR文件的分发或生产过程中,其中没有包括所需的所有类文件。

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

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

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

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

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

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