浅析ClassNotFoundException与NoClassDefFoundError

自建博客地址:https://www.bytelife.net,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客👇

本文作者: Jeffrey
本文链接: https://www.bytelife.net/articles/60306.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!


最近接到电话面试中,面试官问我ClassNotFoundException与NoClassDefFoundError有什么样的区别,至于前者经常遇到,我还是能答上一些,至于后者,完全没遇到过啊,只好瞎编了,都忘记当时是怎么回答的。然后面试官问我他们都会出现在哪些情况,ClassNotFoundException我还可以说出几种情况,可是后者这下不能编了,只好求饶。结果面试官还给我讲解了一下,感觉非常尴尬。 回来以后又查阅了一些相关的资料,并尝试了一下,整理分享给网友。

ClassNotFoundException

这个异常我们遇到的频率还是很高的,先来看看官方文档中的定义:

当应用程序试图使用以下方法通过字符串名加载类时,抛出该异常:

  • Class 类中的 forName 方法。
  • ClassLoader 类中的 findSystemClass 方法。
  • ClassLoader 类中的 loadClass 方法。

但是没有找到具有指定名称的类的定义。 从 1.4 版本开始,此异常已经更新,以符合通用的异常链机制。在构造时提供并通过 getException() 方法访问的“加载类时引发的可选异常”,现在被称为原因,它可以通过 Throwable.getCause() 方法以及与上面提到的“遗留方法”来访问。

也就是说在类加载阶段,通过类全名加载类时,如果不能找到这个类,就会抛出ClassNotFoundException,当然,通常在开发中可能出现该异常的情况总结如下:

  1. 所需要的支持类库放错了地方,并没有放在类路径(CLASSPATH环境变量)里面。
  2. 使用了重复的类库,且版本不一致。导致低版本的被优先使用。
  3. 类名错了,一般是使用Class.forName的时候,手工指定了类名的情况。
  4. 没有导入纯JAVA驱动包。

当然啦,我经常遇到这个异常,尤其是在使用JDBC加载驱动的时候,驱动类的类全名真的是很难记的有木有!

NoClassDefFoundError

可以看到这个错误的类名以Error结尾,因此它属于JVM虚拟机错误,不需要程序员捕获,下图是它的继承结构:

还是同样先来看下官方文档中的定义:

当 Java 虚拟机或 ClassLoader 实例试图在类的定义中加载(作为通常方法调用的一部分或者作为使用 new 表达式创建的新实例的一部分),但无法找到该类的定义时,抛出此异常。 当前执行的类被编译时,所搜索的类定义存在,但无法再找到该定义。

通俗的说,就是编译的时候有这个类,而运行期的时候,这个类找不到了!就会抛出NoClassDefFoundError异常。 想要演示这个异常的出现很简单,只需要在编译好的class文件中将对应类的class文件删除,运行的时候就会抛出这个异常啦! 那么在实际开发中,通常会在哪些情况遇到该异常呢?通常我们在开发过程中,肯定不会刻意的去删除某个class文件,但仍然有出现该异常的情况。 比如我们在使用第三方jar包时,有些SDK也会设定自己的Classpath。编译过程结束后在运行的过程中就要将已开发的应用和所有引入的jar包拷贝到应用服务器的相应目录下才可以运行,而应用服务器使用的Classpath也很有可能与SDK的不同,在这个过程中就有很大的几率造成双方环境不一致。所以很多开发者就会遇到在SDK中可以编译,运行也没有问题,但是同样的程序放到应用服务器上就出现NoClassDefFoundErr这个异常这种情况。

参考文章: 1. JavaTM Platform Standard Edition 6 的 API 规范 2. NoClassDefDoundErr与ClassNotFoundException区别

posted @ 2021-02-25 00:49  JeffreyHu  阅读(223)  评论(0编辑  收藏  举报