NoClassDefFoundError和ClassNotFoundException
NoClassDefFoundError
NoClassDefFoundError 是由于 JVM 或 ClassLoader 实例为了调用某个类的方法或 new 类的新的实例,而试图加载该类的定义时,却无法找到其定义,而抛出的异常。需要注意,对于抛出该异常的情况,试图找到的类的定义在编译时存在,只是在运行时不知所踪。
NoClassDefFoundError 总的来讲有两种情况:① 类文件不存在 ② 类初始化错误
1. 无法找到类文件
java.lang.NoClassDefFoundError: com/example/Foo
2. 类文件初始化错误
NoClassDefFoundError: Could not initialize class {类名}
ps:运行时加载类,执行static块、给static变量初始化等
运行时加载:aop里面,除了我们常用的那种运行时织入(spring aop),还有另外两种方式,一种是编译器织入,即编译好的class已经是织入了切面后的class,再一种就是ltw(load time weaving),也叫类加载期织入。这种织入就是在类首次被加载的时候,对该类的class字节码进行切面织入,从而实现aop功能。
参考:https://blog.csdn.net/deniro_li/article/details/82018648
通常由类的静态成员或静态初始化语句块引起。诸如 private static final MyClass val = new MyClass();
或直接执行于 static {}
代码块中的语句抛出异常,都可能会引发 NoClassDefFoundError。针对第二种这种情况,可以在类的 static initializer 中增加 try catch 语句来捕获异常并输出日志,来了解具体错误内容。
ClassNotFoundException
此外还有一种相似但不同的错误,ClassNotFoundException。它通常由 Java 运行时在无法找到仅在运行过程中才需要加载的类时抛出。
我们常用的Class.forName("xxx.xxx")在如果找不到对应的类的情况下就会报错ClassNotFoundException
注意:ClassNotFoundException是非运行是异常,是可以且必须被捕获或声明为抛出的
其他
NoClassDefFoundError继承自Error,catch Exception无法捕获,需要catch Throwable,因为Error和Exception均继承自Throwable。catch Throwable后若无法处理,重新throw e或者throw new RuntimeException(非运行时异常最终必须catch处理)即可。
思考题
一、在打好jar包的情况下删除某个类,运行时会报什么错
结果:抛出ClassNotFoundException,进而引起NoClassDefFoundError。
二、如果一个类静态代码块初始化失败,其他地方使用时会报什么错?
第一次:抛出ExceptionInInitializerError,计算静态初始化式或静态变量初始化式时发生异常。
第二次:抛出NoClassDefFoundError:
java.lang.NoClassDefFoundError: Could not initialize class xxx
JVM在加载类的时候,会初始化类里的静态变量,或执行静态块,如果这个时候抛出了异常,该类就会加载失败,那么以后任何使用到这个类的地方,都会抛出NoClassDefFoundError异常。