java.lang.ClassNotFoundException與java.lang.NoClassDefFoundError的區別


  以前一直沒有注意過這個問題,前兩天機緣巧合上網查了一下,然后自己測試驗證了一下。雖然網上說法很多,但是關於NoClassDefFoundError並沒有給出一個樣例,所以一直無法理解,索性自己驗證了一下,收獲還不少。

  ClassNotFoundException

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

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

  常見的場景就是:

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

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

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

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

 1 package test321;
 2 
 3 public class test {
 4  public static void main(String[] args) {
 5   try {
 6    Class.forName("test321.hello");
 7   } catch (ClassNotFoundException e) {
 8    e.printStackTrace();
 9   }
10  }
11 }

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

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

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

 1 package test321;
 2 
 3 public class test {
 4  public static void main(String[] args) {
 5   try {
 6    Class.forName("test321.hello1");
 7   } catch (ClassNotFoundException e) {
 8    e.printStackTrace();
 9   }
10  }
11 }

  此時就會報錯!

報錯!
java.lang.ClassNotFoundException: test321.hello1
 at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:190)
 at test321.test.main(test.java:6)

  原因就是找不到指定的string對應的class文件。

  NoClassDefFoundError

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

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

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

  2 類文件存在,但是存在不同的域中

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

  

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

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

  下面做了一個小例子!

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

1 public class test {
2  public static void main(String[] args) {
3   System.out.println("test");
4  }
5 }

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

1 package ccc;
2 
3 public class test {
4  public static void main(String[] args) {
5   System.out.println("test");
6  }
7 }

  很明顯,報錯信息中指出了包的信息!那么怎么辦呢?

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

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

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

 

  參考資料

  1 http://blog.csdn.net/magister_feng/article/details/7459151

  2 http://www.blogjava.net/leekiang/archive/2007/04/26/113810.html

  3 http://blog.sina.com.cn/s/blog_65c507190100hzs0.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM