NoClassDefFoundError和ClassNotFoundException之间的区别是什么?
是什么导致它们被抛出?如何解决这些问题?
在修改现有代码以包含新的jar文件时,我经常遇到这些可抛出的文件。
我已经在客户端和服务器端为一个通过webstart分发的java应用程序击中了它们。
我发现的可能原因是:
未包含在代码客户端build.xml中的包
我们正在使用的新jar缺少运行时类路径
版本与上一个jar冲突
当我今天遇到这些问题时,我采取了一种反复尝试的方法来让事情正常运行。我需要更多的清晰和理解。
给定类装入器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是类型加载错误的一种特殊情况,发生在链接步骤。
与Java API规范的区别如下。
ClassNotFoundException:
当应用程序尝试时抛出
通过类的字符串加载类
名称使用:
类class中的forName方法。
类ClassLoader中的findSystemClass方法。
类ClassLoader中的loadClass方法。
但是没有类的定义
可以找到指定的名称。
NoClassDefFoundError:
抛出如果Java虚拟机或
ClassLoader实例尝试加载
在类的定义中(作为部分)
的正常方法调用或作为的一部分
方法创建一个新实例
表达式)和没有定义的
可以找到类。
搜索的类定义
当前执行时已存在
类被编译,但是定义
再也找不到。
因此,当源代码成功编译时,NoClassDefFoundError似乎发生了,但在运行时,没有找到所需的类文件。这可能发生在JAR文件的分发或生产过程中,其中没有包括所需的所有类文件。
至于ClassNotFoundException,它似乎起源于试图在运行时对类进行反射调用,但程序试图调用的类并不存在。
两者之间的区别是一个是错误,另一个是异常。NoClassDefFoundError是一个错误,它源于Java虚拟机在查找期望查找的类时遇到问题。期望在编译时工作的程序不能运行,因为没有找到类文件,或者与在编译时生成或遇到的类文件不相同。这是一个非常严重的错误,因为该程序不能由JVM启动。
另一方面,ClassNotFoundException是一个异常,所以它在某种程度上是预期的,并且是可以恢复的。使用反射是很容易出错的(因为有一些预期,事情可能不会像预期的那样进行。没有编译时检查来查看所有必需的类是否存在,因此任何查找所需类的问题都会在运行时出现。
当试图通过String引用该类来加载该类时,将抛出ClassNotFoundException。例如,Class.forName()中的参数to是一个字符串,这可能会将无效的二进制名称传递给类加载器。
当遇到可能无效的二进制名称时抛出ClassNotFoundException;例如,如果类名有'/'字符,你一定会得到一个ClassNotFoundException。当直接引用的类在类路径上不可用时,它也会被抛出。
另一方面,NoClassDefFoundError被抛出
when the actual physical representation of the class - the .class file is unavailable,
or the class been loaded already in a different classloader (usually a parent classloader would have loaded the class and hence the class cannot be loaded again),
or if an incompatible class definition has been found - the name in the class file does not match the requested name,
or (most importantly) if a dependent class cannot be located and loaded. In this case, the directly referenced class might have been located and loaded, but the dependent class is not available or cannot be loaded. This is a scenario where the directly referenced class can be loaded via a Class.forName or equivalent methods. This indicates a failure in linkage.
简而言之,当类加载器无法找到或加载类定义时,通常会在new()语句或加载先前不存在的类的方法调用上抛出NoClassDefFoundError(与ClassNotFoundException基于字符串的类加载相反)。
最终,当ClassLoader无法加载类时,由ClassLoader实现抛出ClassNotFoundException实例。大多数自定义类加载器实现执行此操作,因为它们扩展了URLClassLoader。通常类加载器不会在任何方法实现上显式抛出NoClassDefFoundError——这个异常通常是由HotSpot编译器中的JVM抛出的,而不是由类加载器本身抛出的。