这同时也是一个经常被问到的面试题。
字面上的区别
一个是Error,一个是Exception。在Java中Error和Exception是有区别的:我们可以从Exception中恢复程序,但却不应该尝试从Error中恢复程序。
产生的原因
ClassNotFoundException产生的原因
源码注释
JDK8的源码注释是这样写的:
Thrown when an application tries to load in a class through its string name using:
- The forName method in class Class
- The findSystemClass method in class ClassLoader .
- The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
翻译一下
当应用程序尝试使用以下命令通过其字符串名称加载类时:
- 类Class中的forName方法。
- 类ClassLoader中的findSystemClass方法。
- 类ClassLoader中的loadClass方法。
这时找不到具有指定名称的类的定义。这时抛出ClassNotFoundException异常。
以Class.forName方法为例,任意一个类的类名如果被作为参数传,递给这个方法都将导致该类被加载到 JVM 中。如果这个类在类路径中没有被找到,那么此时就会在运行时抛出 ClassNotFoundException 异常。
解决方法
要解决这个问题,就要确保所需的类连同它依赖的包存在于类路径中。当 Class.forName 被调用的时候,类加载器会查找类路径中的类,如果找到了那么这个类就会被成功加载,如果没找到,那么就会抛出ClassNotFountException。
根据注释,会抛出这个异常的有三个方法:
Class.forName、ClassLoader.loadClass和ClassLOader.findSystemClass。
所以,类的动态加载有可能引发ClassNotFoundException异常时,我们可以在此处catch这个异常来处理。
NoClassDefFoundError产生的原因
源码注释
同样,来看一下源码注释
Thrown if the Java Virtual Machine or a *ClassLoader* instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the *new* expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
翻译:
当 Java 虚拟机 或 ClassLoader 实例试图在类的定义中加载(作为通常方法调用的一部分,或者是使用 new 来创建新的对象)时,却找不到类的定义(要查找的类在编译的时候是存在的,运行的时候却找不到了),抛出此异常。
即当前执行的类被编译时,所搜索的类定义存在,但无法再找到该定义。
这是因为Java虚拟机在编译时能找到合适的类,而在运行时不能找到合适的类导致的错误。
由于 NoClassDefFoundError 是有 JVM 引起的,所以不应该尝试捕捉这个错误。
解决方法
查找那些在开发期间存在于类路径下但在运行期间却不在类路径下的类。
NoClassDefFoundError的错误是由于在运行时类加载器在classpath下找不到需要加载的类,所以我们需要把对应的类加载到classpath中,或者检查为什么类在classpath中是不可用的。
两者的区别到底是什么?
ClassNotFoundException 发生在类动态装入阶段。
当应用程序试图通过类的字符串名称,使用常规的三种方法装入类,但却找不到指定名称的类定义时就抛出该异常。
NoClassDefFoundError发生在运行阶段。
在运行时我们想调用某个类的方法或者访问这个类的静态成员的时候,发现这个类不可用,此时Java虚拟机就会抛出NoClassDefFoundError错误。
总结一下,简单来说,NoClassDefFoundError和ClassNotFoundException都是由于在CLASSPATH下找不到对应的类而引起的,通常是缺少对应的jar包,不过,JVM认为:
(1)当应用运行时没有找到对应的引用,则会抛出java.lang.NoClassDefFoundError;
(2)当你在代码中显式加载类(使用Class.forName())时没有找到对应的类,则会抛出java.lang.ClassNotFoundException。
开发者经常遇到的情况是:ClassNotFoundException异常引起了ClassNoDefFoundError。
附上两张很有用的图

