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

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

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

我发现的可能原因是:

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

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


当前回答

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

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

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

其他回答

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

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

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

当ClassLoader没有找到所报告的类时,将抛出ClassNotFoundException。这通常意味着类从CLASSPATH中缺失。这也可能意味着这个类正试图从父类加载器中加载的另一个类中加载,因此子类加载器中的类是不可见的。在应用程序服务器等更复杂的环境中工作时,有时会出现这种情况(WebSphere因此类类加载器问题而臭名昭著)。

人们经常会混淆java.lang.NoClassDefFoundError和java.lang.ClassNotFoundException,但是它们之间有一个重要的区别。例如,一个异常(实际上是一个错误,因为java.lang.NoClassDefFoundError是java.lang.Error的子类)像

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

does not mean that the ActiveMQConnectionFactory class is not in the CLASSPATH. Infact its quite the opposite. It means that the class ActiveMQConnectionFactory was found by the ClassLoader however when trying to load the class, it ran into an error reading the class definition. This typically happens when the class in question has static blocks or members which use a Class that's not found by the ClassLoader. So to find the culprit, view the source of the class in question (ActiveMQConnectionFactory in this case) and look for code using static blocks or static members. If you don't have access the the source, then simply decompile it using JAD.

在检查代码时,假设你发现如下一行代码,确保类SomeClass在CLASSPATH中。

private static SomeClass foo = new SomeClass();

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

如果您想在本地路径中定位类属于哪个jar,可以使用jarscan (http://www.inetfeedback.com/jarscan/)之类的实用程序。您只需指定您想要定位的类以及您希望它开始在jar和zip文件中搜索类的根目录路径。

ClassNotFoundException和NoClassDefFoundError的区别

当试图通过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抛出的,而不是由类加载器本身抛出的。

给定类装入器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是类型加载错误的一种特殊情况,发生在链接步骤。