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

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

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

我发现的可能原因是:

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

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


当前回答

与Java API规范的区别如下。

ClassNotFoundException:

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

NoClassDefFoundError:

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

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

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

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

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

其他回答

与Java API规范的区别如下。

ClassNotFoundException:

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

NoClassDefFoundError:

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

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

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

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

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

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

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

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

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)

例# 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://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

If an error occurs during class loading, then an instance of a subclass of LinkageError must be thrown at a point in the program that (directly or indirectly) uses the class or interface being loaded. If the Java Virtual Machine ever attempts to load a class C during verification (§5.4.1) or resolution (§5.4.3) (but not initialization (§5.5)), and the class loader that is used to initiate loading of C throws an instance of ClassNotFoundException, then the Java Virtual Machine must throw an instance of NoClassDefFoundError whose cause is the instance of ClassNotFoundException.

所以ClassNotFoundException是NoClassDefFoundError的根本原因。 NoClassDefFoundError是类型加载错误的一种特殊情况,发生在链接步骤。