【Java】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)。

參考地址:
https://my.oschina.net/gpzhang/blog/486743
http://shuidexiongdi.iteye.com/blog/2065796

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章