NoClassDefFoundError和ClassNotFoundException之间的区别是什么?
是什么导致它们被抛出?如何解决这些问题?
在修改现有代码以包含新的jar文件时,我经常遇到这些可抛出的文件。
我已经在客户端和服务器端为一个通过webstart分发的java应用程序击中了它们。
我发现的可能原因是:
未包含在代码客户端build.xml中的包
我们正在使用的新jar缺少运行时类路径
版本与上一个jar冲突
当我今天遇到这些问题时,我采取了一种反复尝试的方法来让事情正常运行。我需要更多的清晰和理解。
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,您需要查看是否可以追溯到类第一次加载时,以查找错误的原因。
当我需要复习的时候,我会一遍又一遍地提醒自己
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]
从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虚拟机试图装入类的定义,但找不到该类的定义时抛出。
给定类装入器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是类型加载错误的一种特殊情况,发生在链接步骤。