這同時(shí)也是一個(gè)經(jīng)常被問(wèn)到的面試題徒役。
字面上的區(qū)別
一個(gè)是Error粒褒,一個(gè)是Exception哗蜈。在Java中Error和Exception是有區(qū)別的:我們可以從Exception中恢復(fù)程序茁瘦,但卻不應(yīng)該嘗試從Error中恢復(fù)程序纽竣。
產(chǎn)生的原因
ClassNotFoundException產(chǎn)生的原因
源碼注釋
JDK8的源碼注釋是這樣寫(xiě)的:
Thrown when an application tries to load in a class through its string name using:
- The forName method in class Class
- The findSystemClass method in class ClassLoader .
- The loadClass method in class ClassLoader.
but no definition for the class with the specified name could be found.
翻譯一下
當(dāng)應(yīng)用程序嘗試使用以下命令通過(guò)其字符串名稱(chēng)加載類(lèi)時(shí):
- 類(lèi)Class中的forName方法墓贿。
- 類(lèi)ClassLoader中的findSystemClass方法茧泪。
- 類(lèi)ClassLoader中的loadClass方法。
這時(shí)找不到具有指定名稱(chēng)的類(lèi)的定義聋袋。這時(shí)拋出ClassNotFoundException異常队伟。
以Class.forName方法為例,任意一個(gè)類(lèi)的類(lèi)名如果被作為參數(shù)傳幽勒,遞給這個(gè)方法都將導(dǎo)致該類(lèi)被加載到 JVM 中嗜侮。如果這個(gè)類(lèi)在類(lèi)路徑中沒(méi)有被找到,那么此時(shí)就會(huì)在運(yùn)行時(shí)拋出 ClassNotFoundException 異常啥容。
解決方法
要解決這個(gè)問(wèn)題锈颗,就要確保所需的類(lèi)連同它依賴(lài)的包存在于類(lèi)路徑中。當(dāng) Class.forName 被調(diào)用的時(shí)候咪惠,類(lèi)加載器會(huì)查找類(lèi)路徑中的類(lèi)击吱,如果找到了那么這個(gè)類(lèi)就會(huì)被成功加載,如果沒(méi)找到遥昧,那么就會(huì)拋出ClassNotFountException覆醇。
根據(jù)注釋?zhuān)瑫?huì)拋出這個(gè)異常的有三個(gè)方法:
Class.forName、ClassLoader.loadClass和ClassLOader.findSystemClass炭臭。
所以永脓,類(lèi)的動(dòng)態(tài)加載有可能引發(fā)ClassNotFoundException異常時(shí),我們可以在此處catch這個(gè)異常來(lái)處理鞋仍。
NoClassDefFoundError產(chǎn)生的原因
源碼注釋
同樣憨奸,來(lái)看一下源碼注釋
Thrown if the Java Virtual Machine or a *ClassLoader* instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the *new* expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
翻譯:
當(dāng) Java 虛擬機(jī) 或 ClassLoader 實(shí)例試圖在類(lèi)的定義中加載(作為通常方法調(diào)用的一部分,或者是使用 new 來(lái)創(chuàng)建新的對(duì)象)時(shí)凿试,卻找不到類(lèi)的定義(要查找的類(lèi)在編譯的時(shí)候是存在的排宰,運(yùn)行的時(shí)候卻找不到了),拋出此異常那婉。
即當(dāng)前執(zhí)行的類(lèi)被編譯時(shí)板甘,所搜索的類(lèi)定義存在,但無(wú)法再找到該定義详炬。
這是因?yàn)镴ava虛擬機(jī)在編譯時(shí)能找到合適的類(lèi)盐类,而在運(yùn)行時(shí)不能找到合適的類(lèi)導(dǎo)致的錯(cuò)誤。
由于 NoClassDefFoundError 是有 JVM 引起的呛谜,所以不應(yīng)該嘗試捕捉這個(gè)錯(cuò)誤在跳。
解決方法
查找那些在開(kāi)發(fā)期間存在于類(lèi)路徑下但在運(yùn)行期間卻不在類(lèi)路徑下的類(lèi)。
NoClassDefFoundError的錯(cuò)誤是由于在運(yùn)行時(shí)類(lèi)加載器在classpath下找不到需要加載的類(lèi)隐岛,所以我們需要把對(duì)應(yīng)的類(lèi)加載到classpath中猫妙,或者檢查為什么類(lèi)在classpath中是不可用的。
兩者的區(qū)別到底是什么聚凹?
ClassNotFoundException 發(fā)生在類(lèi)動(dòng)態(tài)裝入階段割坠。
當(dāng)應(yīng)用程序試圖通過(guò)類(lèi)的字符串名稱(chēng)齐帚,使用常規(guī)的三種方法裝入類(lèi),但卻找不到指定名稱(chēng)的類(lèi)定義時(shí)就拋出該異常彼哼。
NoClassDefFoundError發(fā)生在運(yùn)行階段对妄。
在運(yùn)行時(shí)我們想調(diào)用某個(gè)類(lèi)的方法或者訪(fǎng)問(wèn)這個(gè)類(lèi)的靜態(tài)成員的時(shí)候,發(fā)現(xiàn)這個(gè)類(lèi)不可用敢朱,此時(shí)Java虛擬機(jī)就會(huì)拋出NoClassDefFoundError錯(cuò)誤剪菱。
總結(jié)一下,簡(jiǎn)單來(lái)說(shuō)拴签,NoClassDefFoundError和ClassNotFoundException都是由于在CLASSPATH下找不到對(duì)應(yīng)的類(lèi)而引起的琅豆,通常是缺少對(duì)應(yīng)的jar包,不過(guò)篓吁,JVM認(rèn)為:
(1)當(dāng)應(yīng)用運(yùn)行時(shí)沒(méi)有找到對(duì)應(yīng)的引用茫因,則會(huì)拋出java.lang.NoClassDefFoundError;
(2)當(dāng)你在代碼中顯式加載類(lèi)(使用Class.forName())時(shí)沒(méi)有找到對(duì)應(yīng)的類(lèi)杖剪,則會(huì)拋出java.lang.ClassNotFoundException冻押。
開(kāi)發(fā)者經(jīng)常遇到的情況是:ClassNotFoundException異常引起了ClassNoDefFoundError。
附上兩張很有用的圖