JAVA類的靜態載入和動態載入以及NoClassDefFoundError和ClassNotFoundException
阿新 • • 發佈:2018-12-31
我們都知道JAVA初始化一個類的時候可以用new 操作符來初始化,也可通過Class.forName的方式來得到一個Class型別的例項,然後通過這個Class型別的例項的newInstance來初始化.我們把前者叫做JAVA的靜態載入,把後者叫做動態載入.後者在很多框架中經常使用,通過用property檔案的方式指定類名稱.如我們熟悉的在寫JDBC程式碼的時候載入不同資料庫的驅動.
靜態載入的時候如果在執行環境中找不到要初始化的類,丟擲的是NoClassDefFoundError,它在JAVA的異常體系中是一個Error,錯誤.
動態態載入的時候如果在執行環境中找不到要初始化的類,丟擲的是ClassNotFoundException,它在JAVA的異常體系中是一個checked異常,在寫程式碼的時候就需要catch.
下面用例項來演示:ReferencedCls是需要初始化的類,它在一個單獨的jar中,它被StaticReferencingCls和DynamicReferencingCls分別以靜態和動態的方式載入.
將prjT1做成一個jar包,t1.jar.將prjT2做成一個jar包,t2.jar.放在d:/temp資料夾.
以不同的方式執行:package com.test1; public class ReferencedCls { private String str = "test value"; public String getStr() { return str; } public void setStr(String str) { this.str = str; } public ReferencedCls() { System.out.println("Constructor: ReferencedCls"); } } package com.test2; import com.test1.ReferencedCls; public class StaticReferencingCls { public static void main(String[] args) { System.out.println("Started testing static loading..............."); ReferencedCls cls = new ReferencedCls(); System.out.println(cls.getStr()); } } package com.test2; import com.test1.ReferencedCls; public class DynamicReferencingCls { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { System.out.println("Started testing dynamic loading..............."); Class cls = Class.forName("com.test1.ReferencedCls"); ReferencedCls obj = (ReferencedCls)cls.newInstance(); System.out.println(obj.getStr()); } }
1,在執行環境中能找到需要的類時,都正常執行
2,以靜態方式載入,執行環境缺失需要的類,丟擲NoClassDefFoundErrorD:\>java -cp d:/temp/t1.jar;d:/temp/t2.jar com.test2.StaticReferencingCls Started testing static loading............... Constructor: ReferencedCls test value D:\>java -cp d:/temp/t1.jar;d:/temp/t2.jar com.test2.DynamicReferencingCls Started testing dynamic loading............... Constructor: ReferencedCls test value
D:\>java -cp d:/temp/t2.jar com.test2.StaticReferencingCls
Started testing static loading...............
Exception in thread "main" java.lang.NoClassDefFoundError: com/test1/ReferencedCls
at com.test2.StaticReferencingCls.main(StaticReferencingCls.java:9)
Caused by: java.lang.ClassNotFoundException: com.test1.ReferencedCls
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)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
... 1 more
3,以動態方式載入,執行環境缺失需要的類,丟擲ClassNotFoundException,同時在寫程式碼的時候也需要catch這個異常或者宣告這個異常.D:\>java -cp d:/temp/t2.jar com.test2.DynamicReferencingCls
Started testing dynamic loading...............
Exception in thread "main" java.lang.ClassNotFoundException: com.test1.ReferencedCls
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)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at com.test2.DynamicReferencingCls.main(DynamicReferencingCls.java:11)
4,JVM本身使用的方式也是靜態載入,如用JAVA命令執行一個帶main方法的類,這個類在執行環境缺失.D:\>java com.test2.XXXCls
Exception in thread "main" java.lang.NoClassDefFoundError: com/test2/XXXCls
Caused by: java.lang.ClassNotFoundException: com.test2.XXXCls
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)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
Could not find the main class: com.test2.XXXCls. Program will exit.
虛擬機器會延遲載入類,不是import的類都會被載入,只有在第一次使用的時候才載入。比如下面的程式碼,如果不滿足條件,XClass可能在整個執行期間都不會被載入。
if("1".equals(args[0])){
System.out.println(XClass.staticStr);
}