天天看點

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

java裡生成對象有如下兩種方式:

同樣是生成對象,

(一) 在編譯期間

1:  在編譯期間檢查classpath, 如果沒有類定義,編譯沒法通過。

2:  在編譯期間是不會檢查的,不過需要抛出或者自己catch ClassNotFoundException。

 運作期間,如果1編譯時依賴的類不在classpath中(導緻classloader裝載失敗),此時抛出的異常就是NoClassDefFoundError。而如果2在運作期間需要裝載的類不在classpath中,抛出的則是ClassNotFoundException。

(二) 在運作期間

如果 1 編譯時依賴的類不在classpath中(導緻classloader裝載失敗),此時 抛出的異常就是 NoClassDefFoundError。

如果 2 在運作期間需要裝載的類不在classpath中,抛出的則是 ClassNotFoundException。

  ClassNotFoundException這個錯誤,比較常見也好了解。

  原因:就是找不到指定的class。

  常見的場景就是:

  1 調用class的forName方法時,找不到指定的類

  2 ClassLoader 中的 findSystemClass() 方法時,找不到指定的類

  3 ClassLoader 中的 loadClass() 方法時,找不到指定的類

  開發者平時會有這樣一種使用方法,類似JDBC加載驅動!

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  此時,程式會到目前的目錄中尋找指定位置test321.hello這個class。

  并且這個類也是可以正常執行的。

  但是,我們修改一下加載的類名,這樣顯然是找不到指定的類的。

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  此時就會報錯!

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  原因就是找不到指定的string對應的class檔案。

  這個就比較奇葩了,查找其他的資料是說,通過了編譯,但是使用的時候,比如new的時候會出錯。

  通過查找資料,搜集到如下的場景:

  1 類依賴的class或者jar不存在

  2 類檔案存在,但是存在不同的域中

  3 大小寫問題,javac編譯的時候是無視大小的,很有可能你編譯出來的class檔案就與想要的不一樣!這個沒有做驗證。

  

  針對上面的第二點,做了個關于包名的驗證:

  另一種情況就是由于你通過了編譯,但是這個類是有包名的,是以在編譯時需要指定classpath,在使用的時候需要加上包名才可以。

  下面做了一個小例子!

  在沒有包名的情況下,我們看一下正常情況是什麼樣子的。

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  而如果這個類中包含包名,那麼按照上面的方法編譯,使用時就會報錯!

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別
java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  很明顯,報錯資訊中指出了包的資訊!那麼怎麼辦呢?

  在編譯時,加上【   -d .   】這樣可以把目前的目錄加入到classpath中。

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError的差別

  在使用時,加上包名就可以了!

  也就是說,這個含有包名的類,編譯時,需要指定classpath的路徑,并且使用的時候指定包名全路徑,才可以。