NoClassDefFoundError和ClassNotFoundException之间的区别是什么?
是什么导致它们被抛出?如何解决这些问题?
在修改现有代码以包含新的jar文件时,我经常遇到这些可抛出的文件。
我已经在客户端和服务器端为一个通过webstart分发的java应用程序击中了它们。
我发现的可能原因是:
未包含在代码客户端build.xml中的包
我们正在使用的新jar缺少运行时类路径
版本与上一个jar冲突
当我今天遇到这些问题时,我采取了一种反复尝试的方法来让事情正常运行。我需要更多的清晰和理解。
当我需要复习的时候,我会一遍又一遍地提醒自己
ClassNotFoundException
类层次结构
ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable
在调试
Required jar,类路径中缺少类。
验证所有必需的jar都在jvm的类路径中。
NoClassDefFoundError
类层次结构
NoClassDefFoundError extends LinkageError extends Error extends Throwable
在调试
Problem with loading a class dynamically, which was compiled properly
Problem with static blocks, constructors, init() methods of dependent class and the actual error is wrapped by multiple layers [especially when you use spring, hibernate the actual exception is wrapped and you will get NoClassDefError]
When you face "ClassNotFoundException" under a static block of dependent class
Problem with versions of class.
This happens when you have two versions v1, v2 of same class under different jar/packages, which was compiled successfully using v1 and v2 is loaded at the runtime which doesn't has the relevant methods/vars& you will see this exception. [I once resolved this issue by removing the duplicate of log4j related class under multiple jars that appeared in the classpath]
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,您需要查看是否可以追溯到类第一次加载时,以查找错误的原因。
从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虚拟机试图装入类的定义,但找不到该类的定义时抛出。
与Java API规范的区别如下。
ClassNotFoundException:
当应用程序尝试时抛出
通过类的字符串加载类
名称使用:
类class中的forName方法。
类ClassLoader中的findSystemClass方法。
类ClassLoader中的loadClass方法。
但是没有类的定义
可以找到指定的名称。
NoClassDefFoundError:
抛出如果Java虚拟机或
ClassLoader实例尝试加载
在类的定义中(作为部分)
的正常方法调用或作为的一部分
方法创建一个新实例
表达式)和没有定义的
可以找到类。
搜索的类定义
当前执行时已存在
类被编译,但是定义
再也找不到。
因此,当源代码成功编译时,NoClassDefFoundError似乎发生了,但在运行时,没有找到所需的类文件。这可能发生在JAR文件的分发或生产过程中,其中没有包括所需的所有类文件。
至于ClassNotFoundException,它似乎起源于试图在运行时对类进行反射调用,但程序试图调用的类并不存在。
两者之间的区别是一个是错误,另一个是异常。NoClassDefFoundError是一个错误,它源于Java虚拟机在查找期望查找的类时遇到问题。期望在编译时工作的程序不能运行,因为没有找到类文件,或者与在编译时生成或遇到的类文件不相同。这是一个非常严重的错误,因为该程序不能由JVM启动。
另一方面,ClassNotFoundException是一个异常,所以它在某种程度上是预期的,并且是可以恢复的。使用反射是很容易出错的(因为有一些预期,事情可能不会像预期的那样进行。没有编译时检查来查看所有必需的类是否存在,因此任何查找所需类的问题都会在运行时出现。
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)