NoClassDefFoundError
和ClassNotFoundException
什麼區別? html
是什麼致使它們被拋出? 如何解決? java
在修改現有代碼以包含新的jar文件時,我常常遇到這些throwables。 我在客戶端和服務器端都經過Webstart分發了一個Java應用程序。 數據庫
我遇到的可能緣由: apache
build.xml
中的軟件包 今天,當我遇到這些問題時,我採起了走錯一步的方法來使事情順利進行。 我須要更多的清晰度和理解。 api
NoClassDefFoundError
基本上是一個連接錯誤。 當您嘗試實例化一個對象時會發生這種狀況(靜態地使用「 new」),而在編譯過程當中則找不到該對象。 服務器
ClassNotFoundException
更通用,是當您嘗試使用不存在的類時的運行時異常。 例如,您在函數中具備接受接口的參數,而且有人傳入實現該接口的類,但您無權訪問該類。 它還介紹了動態類加載的狀況,例如使用loadClass()
或Class.forName()
。 函數
與Java API規範的區別以下。 網站
對於ClassNotFoundException
: ui
當應用程序嘗試使用其字符串名稱經過其字符串名稱加載類時拋出: spa
- 類
Class
的forName
方法。- 類
ClassLoader
的findSystemClass
方法。- 類
ClassLoader
的loadClass
方法。但找不到具備指定名稱的類的定義。
若是Java虛擬機或
ClassLoader
實例嘗試加載類的定義(做爲常規方法調用的一部分或使用新表達式建立新實例的一部分)而拋出,則ClassLoader
的定義。當前正在編譯的類在編譯時就存在搜索到的類定義,可是沒法再找到該定義。
所以,彷佛在成功編譯源代碼時發生了NoClassDefFoundError
,可是在運行時未找到所需的class
文件。 這多是在JAR文件的分發或生產中可能發生的狀況,其中並未包括全部必需的class
文件。
至於ClassNotFoundException
,彷佛是因爲試圖在運行時對類進行反射性調用而引發的,但程序嘗試調用的類不存在。
二者的區別在於,一個是Error
,另外一個是Exception
。 使用NoClassDefFoundError
是一個Error
,它是因爲Java虛擬機在查找其指望查找的類時遇到問題而引發的。 因爲找不到class
文件,或者與編譯時生成或遇到的class
文件不一樣,預期沒法在編譯時工做的程序沒法運行。 這是一個很是嚴重的錯誤,由於該程序沒法由JVM啓動。
另外一方面, ClassNotFoundException
是Exception
,所以在某種程度上是能夠預期的,而且能夠恢復。 使用反射是容易出錯的(由於有些指望可能不會按預期進行。沒有編譯時檢查以確保全部必需的類都存在,所以查找所需類的任何問題都會在運行時出現。
嘗試經過String引用加載類時,拋出ClassNotFoundException 。 例如,Class.forName()中的參數to是一個字符串,這增長了將無效二進制名稱傳遞給類加載器的可能性。
當遇到可能無效的二進制名稱時,將引起ClassNotFoundException; 例如,若是類名帶有'/'字符,則勢必會收到ClassNotFoundException。 當直接引用的類在類路徑上不可用時,也會拋出該錯誤。
另外一方面,拋出NoClassDefFoundError
簡而言之,當類加載器沒法找到或加載類定義時,一般會在加載之前不存在的類的new()語句或方法調用上引起NoClassDefFoundError(與ClassNotFoundException的基於字符串的類加載相反) s)。
最終,當沒法加載類時,由ClassLoader實現拋出ClassNotFoundException實例。 大多數自定義類加載器實現都執行此操做,由於它們擴展了URLClassLoader。 一般,類加載器不會在任何方法實現上顯式拋出NoClassDefFoundError-一般從HotSpot編譯器中的JVM拋出此異常,而不是由類加載器自己拋出。
當ClassLoader未找到報告的類時,將引起ClassNotFoundException。 這一般意味着CLASSPATH中缺乏該類。 這也可能意味着該類正試圖從另外一個已加載到父類加載器中的類中加載,所以子類加載器中的類不可見。 在更復雜的環境(例如App Server)中工做時,有時會是這種狀況(WebSphere臭名昭著的類加載器問題)。
人們一般傾向於將java.lang.NoClassDefFoundError
與java.lang.ClassNotFoundException
混淆,可是有一個重要的區別。 例如一個異常(其實是一個錯誤,由於java.lang.NoClassDefFoundError
是java.lang.NoClassDefFoundError
的子類)
java.lang.NoClassDefFoundError: org/apache/activemq/ActiveMQConnectionFactory
這並不意味着ActiveMQConnectionFactory類不在CLASSPATH中。 其實是相反的。 這意味着ClassLoader找到了ActiveMQConnectionFactory類,可是在嘗試加載該類時,在讀取類定義時遇到了錯誤。 當所涉及的類具備使用ClassLoader找不到的類的靜態塊或成員時,一般會發生這種狀況。 所以,要找到罪魁禍首,請查看相關類的源(在本例中爲ActiveMQConnectionFactory),並使用靜態塊或靜態成員查找代碼。 若是您無權訪問源,則只需使用JAD對其進行反編譯。
在檢查代碼時,假設您發現以下所示的代碼行,請確保CLASSPATH中的類SomeClass。
private static SomeClass foo = new SomeClass();
提示:要找出一個類所屬的jar,可使用網站jarFinder。 這使您可使用通配符指定類名,並在其jar數據庫中搜索該類。 jarhoo容許您執行相同的操做,但再也不無償使用。
若是要在本地路徑中找到類所屬的jar,可使用jarscan( http://www.inetfeedback.com/jarscan/ )之類的實用程序。 您只需指定要查找的類以及您但願它開始在jar和zip文件中搜索該類的根目錄路徑。
來自http://www.javaroots.com/2013/02/classnotfoundexception-vs.html :
ClassNotFoundException
:當類加載器在類路徑中找不到所需的類時發生。 所以,基本上,您應該檢查您的類路徑並將該類添加到類路徑中。
NoClassDefFoundError
:這更難調試和查找緣由。 當在編譯時存在所需的類時拋出此錯誤,可是在運行時更改或刪除了這些類,或者類的靜態初始化引起了異常。 這意味着要加載的類存在於類路徑中,可是該類所需的一個類已被編譯器刪除或加載失敗。 所以,您應該看到依賴於此類的類。
範例 :
public class Test1 { } public class Test { public static void main(String[] args) { Test1 = new Test1(); } }
如今,在編譯完兩個類以後,若是刪除Test1.class文件並運行Test class,它將拋出
Exception in thread "main" java.lang.NoClassDefFoundError: Test at Test1.main(Test1.java:5) Caused by: java.lang.ClassNotFoundException: Test at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 1 more
ClassNotFoundException
:當應用程序嘗試經過其名稱加載類時拋出,但找不到具備指定名稱的類的定義。
NoClassDefFoundError
:若是Java虛擬機嘗試加載類的定義而且找不到該類的定義,則拋出該異常。