閱讀749 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Class.forName() vs Class.loadClass()

ClassLoader.loadClass()與Class.forName()都是通過反射來構造類的方法。但是他們的用法還是有一定區別的。
在講區別之前,先把類的加載過程整理一下。

在Java中,類裝載器把一個類裝入Java虛擬機中,要經過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:

裝載:查找和導入類或接口的二進製數據;

鏈接:執行下麵的校驗、準備和解析步驟,其中解析步驟是可以選擇的;

校驗:檢查導入類或接口的二進製數據的正確性;

準備:給類的靜態變量分配並初始化存儲空間;

解析:將符號引用轉成直接引用;

初始化:激活類的靜態變量的初始化Java代碼和靜態Java代碼塊。

Class.forName(className)方法,
其實調用的方法是 Class.forName(className,true,classloader);
注意看第2個boolean參數,它表示的意思,在loadClass後必須初始化。
比較下前麵準備jvm加載類的知識,可以清晰的看到在執行過此方法後,目標對象的 static塊代碼已經被執行,static參數也已經被初始化。

ClassLoader.loadClass(className)方法,
其實調用的方法是 ClassLoader.loadClass(className,false);
注意看第2個 boolean參數,該參數表示目標對象被裝載後不進行鏈接,這就意味這不會去執行該類靜態塊中間的內容。

因此2者的區別就顯而易見了。

一般情況下,這兩個方法效果一樣,都能裝載Class。但如果程序依賴於Class是否被初始化,就必須用Class.forName(name)了。

例如,在JDBC編程中,常看到這樣的用法,Class.forName("com.mysql.jdbc.Driver"),如果換成了 getClass().getClassLoader().loadClass("com.mysql.jdbc.Driver"),就不行。
為什麼呢?打開com.mysql.jdbc.Driver的源代碼看看,

//
// Register ourselves with the DriverManager
//
static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
} 

Driver在static塊中會注冊自己到java.sql.DriverManager。而static塊就是在Class的初始化中被執行。所以這個地方就隻能用Class.forName(className)。

最後更新:2017-06-18 09:32:14

  上一篇:go  :hover事件觸發自己的:afert偽類事件(.class:hover::after)
  下一篇:go  查看centos服務器硬盤狀態信息