最近看到一个面试题,问ClassNotFoundException和NoClassDefFoundError的区别。平时没有专门思考过这个问题,藉此机会分析一下。
一个直观的区别是一个是异常,一个是错误,异常和错误的区别就可以先讲一波。
然后其他的相同点和不同点在看到的一篇非常好的英文文章中有详细的讲述,翻译在此。
1. 介绍
ClassNotFoundException 和NoClassDefFoundError都发生在JVM在classpath下找不到所需的类时。
虽然看起来很相似,但是两者有很大不同。
本文我们将介绍他们是怎样出现的以及怎么去解决这些错误。
2. ClassNotFoundException
当应用尝试在类路径中用全限量名去加载某个类时,如果找你不到它的定义就会报CLassNotFoundException 。它是一个可检测异常。
通常出现在用Class.forName(), ClassLoader.loadClass()或 ClassLoader.findSystemClass()这三个方法加载类的时候。我们在使用反射的时候,要特别注意这个异常。
下面这个例子,我们尝试加载的JDBC驱动没有添加到类路径中(没有添加依赖),将会报ClassNotFoundException。
1. @Test(expected = ClassNotFoundException.class) 2. public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() 3. throws ClassNotFoundException { 4. Class.forName("oracle.jdbc.driver.OracleDriver"); 5. }
3. NoClassDefFoundError
NoClassDefFoundError是一种致命错误。
当JVM尝试通过new关键字创建一个类实例或者方法调用来加载一个类时找不到这个类的定义就会出现这个错误。
通常是编译时正常编译,但是运行时找不到这个类。
通常发生在执行动态代码块或者初始化静态字段时报了异常,从而导致类初始化失败而引发NoClassDefFoundError。
1. public class ClassWithInitErrors { 2. static int data = 1 / 0; 3. }
1. public class NoClassDefFoundErrorExample { 2. public ClassWithInitErrors getClassWithInitErrors() { 3. ClassWithInitErrors test; 4. try { 5. test = new ClassWithInitErrors(); 6. } catch (Throwable t) { 7. System.out.println(t); 8. } 9. test = new ClassWithInitErrors(); 10. return test; 11. } 12. }
编写测试用例
1. @Test(expected = NoClassDefFoundError.class) 2. public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() { 3. 4. NoClassDefFoundErrorExample sample 5. = new NoClassDefFoundErrorExample(); 6. sample.getClassWithInitErrors(); 7. }
4. 解决办法
排查和修复这两个问题有时候会非常耗时。
他们的主要原因是运行时类路径中类文件不可用。
下面是几点具体的原因:
- 排查所需的jar包是否在类路径中,如果没有就添加进去。
- 如果发现类在classpath里面,很有可能是classpath被重写了,需要再次确定应用准确的classpath
- 依赖包发生了冲突,比如应该依赖高版本jar包,但又其它包传递依赖了低版本jar包,导致高版本中某些类找不到。
- 如果应用中用到了多个类加载器,一个类加载器加载的类,无法再其他的类加载器中使用。
5、总结
ClassNotFoundException与NoClassDefException核心区别是,前者强调运行时无法匹配到指定参数名称的类,后者强调编译时没问题,运行时却无法实例化一个类。
最常见的解决方法是检查是否依赖了相关包或者相关包是否有冲突。
英文原文:https://www.baeldung.com/java-classnotfoundexception-and-noclassdeffounderror
源代码地址:https://github.com/eugenp/tutorials/tree/master/core-java-lang