1. 程式人生 > >JAVA類的靜態載入和動態載入以及NoClassDefFoundError和ClassNotFoundException

JAVA類的靜態載入和動態載入以及NoClassDefFoundError和ClassNotFoundException

我們都知道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資料夾.


JAVA程式碼如下:
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,在執行環境中能找到需要的類時,都正常執行
D:\>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
2,以靜態方式載入,執行環境缺失需要的類,丟擲NoClassDefFoundError
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);
}