本文翻譯自:
Difference between NoClassDefFoundError vs ClassNotFoundExcepiton in Java
如果JVM或者ClassLoader在載入類時找不到對應的類,就會引發NoClassDefFoundError和ClassNotFoundException,這兩種錯誤都非常嚴重。由於不同的ClassLoader會從不同的地方載入類,有時是錯誤的CLASSPATH引發這類錯誤,有時是某個庫的jar包缺失引發這類錯誤。NoClassDefFoundError和ClassNotFoundException之間存在一些細微的不同點。
NoClassDefFoundError表示該類在編譯階段還可以找到,但是在執行Java應用的時候找不到了,有時靜態塊的初始化過程會導致NoClassDefFoundError。
另外一方面,ClassNotFoundException和編譯期沒什麼關係,當你在程式執行時利用反射載入類時,就可能遇到ClassNotFoundException異常,例如載入SQL驅動時,對應的類載入器找不到驅動類。除了這些基本的不同,我們可以看看別的不同,以加深對NoClassDefFoundError和ClassNotFoundException的理解。
NoClassDefFoundError vs ClassNotFoundException
簡單來說,NoClassDefFoundError和ClassNotFoundException都是由於在CLASSPATH下找不到對應的類而引起的,通常是缺少對應的jar包,不過,JVM認為:(1)當應用執行時沒有找到對應的取用,則會丟擲java.lang.NoClassDefFoundError;(2)當你在程式碼中顯式載入類(使用Class.forName())時沒有找到對應的類,則會丟擲java.lang.ClassNotFoundException。開發者經常遇到的情況是:ClassNotFoundException異常引起了ClassNoDefFoundError。
1.NoClassDefFoundError是Error,是unchecked,因此也不需要使用try-catch或者finally陳述句塊包圍;另外,ClassNotFoundException是受檢異常(checked Exception),因此需要使用try-catch陳述句塊或者try-finally陳述句塊包圍,否則會導致編譯錯誤。
2.如果你在J2EE開發中遇到NoClassDefFoundError,那麼最有可能的原因就是存在多個類載入器和多個標的類,即我們常說的Jar包衝突——關於Jar包衝突,一般可以使用下麵兩種方法解決:
-
使用Maven Helper 這個外掛,可以排除掉大部分jar包衝突;
-
根據命令
mvn dependency:tree-Dverbose-Dincludes=:logback-classic
3.呼叫Class.forName()、ClassLoader.findSystemClass()和ClassLoader.loadClass()等方法時可能會引起java.lang.ClassNotFoundException
4.NoClassDefFoundError是連結錯誤,發生在連結階段,當解析取用的時候找不到對應的類,就會丟擲java.lang.NoClassDefFoundError;ClassNotFoundException是異常,發生在執行階段。
最後,這裡有一頁非常好的PPT,總結了這兩種異常的不同點:
推薦一個我最近在學的JVM課程,來自Oracle高階研究員鄭宇迪在極客時間的JVM專欄,目前更新了12篇文章,我基本都跟下來了,質量值得信賴。
整個專欄將分為四大模組。
-
基本原理:剖析 Java 虛擬機器的執行機制,逐一介紹 Java 虛擬機器的設計決策以及工程實現;
-
高效實現:探索 Java 編譯器,以及內嵌於 Java 虛擬機器中的即時編譯器,幫助你更好地理解 Java 語言特性,繼而寫出簡潔高效的程式碼;
-
程式碼最佳化:介紹如何利用工具定位並解決程式碼中的問題,以及在已有工具不適用的情況下,如何打造專屬輪子;
-
虛擬機器黑科技:介紹甲骨文實驗室近年來的前沿工作之一 GraalVM。包括如何在 JVM 上高效執行其他語言;如何混搭這些語言,實現 Polyglot;如何將這些語言事前編譯(Ahead-Of-Time,AOT)成機器指令,單獨執行甚至嵌入至資料庫中執行。