ClassNotFoundException 和 NoClassDefFoundError 有什么区别?
ClassNotFoundException 是个 Exception,是使用类似 Class.forName() 等方法动态加载类时,由于找不到对应的类而发生的 checked exception。
NoClassDefFoundError 是个 Error,是指一个 class 在编译时存在,在运行时找不到了 class 文件了。
一、ClassNotFoundException
典型触发场景,调用以下方法时加载失败:
Class.forName(),
ClassLoader.loadClass()
ClassLoader.findSystemClass()
通过反射机制初始化类
如加载数据库驱动时:
public class ExceptionTest { public static void main(String[] args)throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); } } 复制代码
二、NoClassDefFoundError
典型触发场景如下:
1.编译时存在某个类,但是运行时却找不到
public class A { public void hello(){ System.out.println("hello, world."); } } class B { public static void main(String[] args) { A a = new A(); } } 复制代码
上面的 Java 类编译后会生成两个类文件,一个 A.class,一个B.class。
现在我在编译后,删掉了 A 的 class 文件,然后直接执行 B 的 main 方法,就会抛出 NoClassDefFoundError 错误,因为当执行到 A a=new A() 这一步的时候,JVM认为这个类肯定在当前的 classpath 里面的,要不然编译都不会通过。
既然它存在,那么在 JVM 里面一定能找到,如果不能找到,那就说明出大事了,因为编译和运行不一致,所以直接抛出这个 ERROR,代表问题很严重。
2.一个类没有初始化成功,其他类调用这个类,导致执行失败
初始化失败的类:
public class InitFail { static double divideZero = 1/0;//故意使得类初始化失败. public static void print(){ System.out.println("123"); } } 复制代码
调用如下:
public static void main(String[] args) { try { double divideZero = InitFail.divideZero; }catch (Throwable e){ //此处,必须用Throwable,用Exception会直接退出. System.out.println(e); } //继续使用. InitFail.print(); } 复制代码
这种情况比较特殊,并不是因为编译时和运行时环境不一致导致的,而是对于一个类如果初始化失败后,还继续使用。
JVM 会认为是不正常的,由于它第一次调用已经失败,JVM 就会假设后面继续调用肯定仍然会失败,所以直接抛 ERROR 给客户端。
三、总结
用一个表格总结一下:
作者:陈有余
链接:https://juejin.cn/post/7020603406096007204