天天看點

Class.forName和ClassLoader.loadClass的比較

class的裝載分了三個階段,loading(加載),linking(連結)和initializing(初始化),分别定義在the java language specification的12.2,12.3和12.4。 

class.forname(classname)實際上是調用class.forname(classname, true, this.getclass().getclassloader())。注意第二個參數,是指class被loading後是不是必須被初始化。 

classloader.loadclass(classname)實際上調用的是classloader.loadclass(name, false),第二個參數指出class是否被link。 

差別就出來了。class.forname(classname)裝載的class已經被初始化,而classloader.loadclass(classname)裝載的class還沒有被link。 

一般情況下,這兩個方法效果一樣,都能裝載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)。 

加載:這是由類加載器執行的。該步驟将查找位元組碼(通常在classpath所指定的路徑中查找,但這并非是必須的),并從這些位元組碼 

          中建立一個class對象。 

連結:在連結階段将驗證類中的位元組碼,為靜态域配置設定存儲空間,并且如果必須的話,将解析這個類建立的對其他類的所有引用。 

初始化:如果該類具有超類,則對其初始化,執行靜态初始化器和靜态初始化塊。 

初始化對被延遲到了對靜态方法(構造器隐式地是靜态的)或者非常數靜态域進行首次引用時才執行。 

特别說明:尊重作者的勞動成果,轉載請注明出處哦~~~http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytpo7