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

Java NoClassDefFoundError和ClassNotFoundException之间的原因和区别是什么?,java,classpath,noclassdeffounderror,classnotfoundexception,Java,Classpath,Noclassdeffounderror,Classnotfoundexception,NoClassDefFoundError和ClassNotFoundException之间有什么区别 是什么原因导致它们被抛出?如何解决这些问题 在修改现有代码以包含新的jar文件时,我经常会遇到这些问题。 对于通过webstart分发的java应用程序,我在客户端和服务器端都找到了它们 我遇到的可能原因: 代码客户端的build.xml中未包含的包 我们正在使用的新JAR缺少运行时类路径 版本与以前的jar冲突 当我今天遇到这些问题时,我会采取循序渐进的方法来解决问题。我需要更加清晰和理解。N

NoClassDefFoundError和ClassNotFoundException之间有什么区别

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

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

我遇到的可能原因:

代码客户端的build.xml中未包含的包 我们正在使用的新JAR缺少运行时类路径 版本与以前的jar冲突 当我今天遇到这些问题时,我会采取循序渐进的方法来解决问题。我需要更加清晰和理解。

NoClassDefFoundError基本上是一种链接错误。当您尝试用new静态实例化一个对象时,就会发生这种情况,而在编译过程中找不到它


ClassNotFoundException更一般,当您尝试使用不存在的类时,它是一个运行时异常。例如,在接受接口的函数中有一个参数,有人传入实现该接口的类,但您无权访问该类。它还涵盖了动态类加载的情况,例如使用loadClass或class.forName。

与Java API规范的区别如下

用于:

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

类中的forName方法。 类加载器中的findSystemClass方法。 类类加载器中的loadClass方法。 但对于具有 无法找到指定的名称

用于:

如果Java虚拟机或 ClassLoader实例尝试加载 在类作为一部分的定义中 属于普通方法调用或作为 使用新实例创建新实例 表达式,但不定义 可以找到类

已搜索类定义 当前正在执行时存在 类已编译,但定义 再也找不到了

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

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

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

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

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

遇到可能无效的二进制名称时抛出ClassNotFoundException;例如,如果类名具有“/”字符,则您必须获得ClassNotFoundException。当直接引用的类在类路径上不可用时,也会抛出它

    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)
另一方面,它被抛出

当类的实际物理表示形式.class文件不可用时, 或者类已经加载到另一个类加载器中,通常父类加载器会加载该类,因此不能再次加载该类, 或者,如果发现不兼容的类定义-类文件中的名称与请求的名称不匹配, 或者最重要的是,如果无法定位和加载依赖类。在这种情况下,可能已经找到并加载了直接引用的类,但依赖类不可用或无法加载。在这种情况下,可以通过class.forName或等效方法加载直接引用的类。这表明悬挂机构出现故障。 简而言之,NoClassDefFoundError通常在加载以前不存在的类的新语句或方法调用时抛出,而不是基于字符串加载类 当类加载器无法找到或加载类定义时,类NotFoundException的es


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

当类加载器找不到报告的类时,会抛出ClassNotFoundException。这通常意味着类路径中缺少该类。这也可能意味着所讨论的类正试图从父类装入器中装入的另一个类装入,因此子类装入器中的类不可见。在应用服务器等更复杂的环境中工作时,有时会出现这种情况。WebSphere因此类类加载器问题而臭名昭著

人们通常倾向于混淆java.lang.NoClassDefFoundError和java.lang.ClassNotFoundException,但是有一个重要的区别。例如,一个异常是一个错误,因为java.lang.NoClassDefFoundError是java.lang.error的一个子类

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory
并不意味着ActiveMQConnectionFactory类不在类路径中。事实恰恰相反。这意味着类加载器找到了类ActiveMQConnectionFactory,但是在尝试加载该类时,它在读取类定义时遇到错误。这通常发生在所讨论的类具有静态块或成员,而这些静态块或成员使用类加载器找不到的类时。因此,要找到罪魁祸首,请在本例中查看相关类ActiveMQConnectionFactory的源代码,并查找使用静态块或静态成员的代码。如果您没有访问源代码的权限,那么只需使用JAD对其进行反编译

在检查代码时,假设您找到一行代码,如下所示,请确保该类在类路径中包含SomeClass

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


如果您想在本地路径中找到一个类所属的jar,可以使用类似jarscan的实用程序。您只需指定要定位的类以及要在JAR和zip文件中开始搜索该类的根目录路径。

当代码运行新的Y并且找不到Y类时,会发生NoClassDefFoundError NCDFE

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

如果发生这种情况,JVM将记住加载X NCDFE的结果,并且每当您请求Y时,JVM只会抛出一个新的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();} } } 第一次调用导致类加载器在找不到类时抛出ClassNotFoundException,该类必须封装在未检查的NoClassDefFoundError中,因为有问题的代码new b应该可以正常工作

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

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

获取每个错误的原因是什么,以及如何处理此类错误的任何思考过程是什么

他们关系密切。当Java按名称查找特定类并且无法成功加载该类时,会引发ClassNotFoundException。当Java查找链接到某些现有代码中的类,但由于某种原因(例如错误的类路径、错误的Java版本、错误的库版本)而找不到该类时,会抛出NoClassDefFoundError,这是完全致命的,因为它表明出现了严重错误


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

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

ClassNotFoundException:正如cletus所说,您使用接口时继承的接口类不在类路径中。例如,服务提供者模式或尝试查找一些不存在的类 NoClassDefFoundError:在t 找不到给定类的依赖项 在实践中,错误可能会以静默方式抛出,例如,您提交了一个计时器任务,而在计时器任务中它会抛出错误,而在大多数情况下,您的程序只捕获异常。然后定时器主循环结束,没有任何信息。与NoClassDefFoundError类似的错误是,当静态初始值设定项或静态变量的初始值设定项引发异常时。

来自:

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

    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:这更难调试并找到原因。当在编译时存在所需的类,但在运行时更改或删除这些类,或者类的静态初始化引发异常时,会引发此异常。这意味着要加载的类存在于类路径中,但该类所需的一个类被编译器删除或加载失败。所以您应该看到依赖于这个类的类

例如:

现在,在编译这两个类之后,如果删除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


两者都是运行时异常。

给定类加载器系统操作:

这篇文章帮助我理解了其中的差异:

如果在类加载期间发生错误,则 LinkageError的子类必须在程序中 直接或间接使用正在加载的类或接口

如果Java虚拟机在运行期间尝试加载类C 验证§5.4.1或决议§5.4.3,但不包括初始化 §5.5,以及用于启动C类加载的类加载程序 抛出ClassNotFoundException的实例,然后 计算机必须抛出原因为的NoClassDefFoundError实例 ClassNotFoundException的实例

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

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

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

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

区别:

ClassNotFoundException:

类加载器无法验证链接中的字节码。 ClassNotFoundException是一种检查异常,当应用程序试图通过其完全限定名加载类,但在类路径上找不到其定义时,会发生该异常。 当使用ClassLoader.loadClass、class.forName和ClassLoader.findSystemClass在运行时提供类名,从而涉及到类的显式加载时,会出现ClassNotFoundException。 NoClassDefFoundError:

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

NoClassDefFoundError和ClassNotFoundException都与类在运行时的不可用性有关。 ClassNotFoundException和NoClassDefFoundError都与Java类路径相关。
ClassNotFoundException与NoClassDefFoundError之间的差异


当我需要刷新时,我会反复提醒自己以下几点

ClassNotFoundException

类层次结构

调试时

必需的jar,类路径中缺少类。 验证所有必需的JAR都在jvm的类路径中。 NoClassDefFoundError

类层次结构

调试时

动态加载已正确编译的类时出现问题 静态块问题,cons 依赖类的构造函数、init方法和实际错误被多层包装[特别是当您使用spring、hibernate时,实际异常被包装,您将得到NoClassDefError] 当您面对依赖类的静态块下的ClassNotFoundException时 类的版本有问题。 当您在不同的jar/包下有相同类的两个版本v1、v2时会发生这种情况,这是使用v1成功编译的,v2在运行时加载的,运行时没有相关的方法/变量&您将看到此异常。[我曾经通过在类路径中出现的多个JAR下删除log4j相关类的副本来解决这个问题] ClassNotFoundException是一个选中的异常,当我们告诉JVM使用class.forName或ClassLoader.findSystemClass或ClassLoader.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)
大多数情况下,当您尝试运行应用程序而不使用所需的JAR文件更新类路径时,会发生此异常。例如,在执行JDBC代码以连接到数据库(即MySQL)时,您可能会看到此异常,但您的类路径没有JAR

NoClassDefFoundError错误发生在JVM尝试加载特定类时,该类是代码执行的一部分,作为普通方法调用的一部分,或作为使用new关键字创建实例的一部分,并且该类不在类路径中,但在编译时存在,因为要执行程序,需要编译如果您尝试使用不存在的类,编译器将引发编译错误

以下是简要说明


您可以阅读以了解更多详细信息。

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。ClassNotFoundException表示CL没有看到.class文件。NoClassDefFoundError意味着.class文件在那里它不可加载可能是JNI错误。这个答案与回答形式coobird不矛盾吗?我尝试了类似的静态块示例。我的类Class1有静态变量private static B foo=new B;编译之后,我从bin文件夹中删除了B.class文件。现在从第三类的Main方法开始,当我创建Class1的对象时。错误如下:-线程主java.lang.NoClassDefFoundError中的异常:spring/B。。。。。。。。因此,它确切地提到了它没有找到的类,即在静态块中引用的类,而不是外部类。因此,这与此答案相反。+1对于有关的澄清并不意味着ActiveMQConnectionFactory类不在CLASSPATHNoClassDefFoundError中,通常在静态块引发问题异常时发生阻止或静态字段初始化该类,因此无法成功初始化该类。upvote。一个是错误,另一个是例外:Upvote用于提及“类文件中的名称与请求的名称不匹配”。这是一个很常见的原因。如何使用-verbose或一些类似的选项来运行JVM,具体取决于特定的JVM?如果使用jni,可能-verbose:class,可能-verbose:class:jni,但我不确定语法。-verbose:class:jni是错误的,但您可以传递两个单独的选项:-verbose:class-verbose:jni。如何使用-verbose运行JVM,或者根据特定JVM使用类似的选项?如果使用jni,则可能为-verbose:class,可能为-verbose:class:jni,但我不确定语法。如果这是有用的,也许您可以显示结果。无论是-verbose:class还是-verbose:jni都不会给出任何与缺少的类相关的额外输出。感谢您尝试,即使结果令人失望。另外,我后来发现-verbose:class:jni是错误的:必须指定两个单独的选项:-verbose:class-verbose:jni。最后一句*1000000:如果您看到没有根本原因的NCDFE,您需要查看是否可以追溯到第一次加载类时,以找到错误的原因。我经常发现使用-verbose运行JVM,例如-verbose:class-verbose:jni很有帮助,但mogsie在回答下面报告说,这没有提供额外的有用信息:不是非常清楚。类路径中未更新的是vague/impercis E这是关于JAR不在类路径中,或者JAR的错误版本在类路径上的问题。还有拼写错误。唉,既然你把你的信息贴成了一张时髦的图片,我们就无法解决这个问题。
    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)