2011-07-10 273 views
2

可能重複的區別:
Difference betweeen Loading a class using ClassLoader and Class.forName什麼ClassLoader.load(名稱)和的Class.forName(名稱)

據我所知,在的Java提供了兩種方法來初始化一個名字的類。

  • 公共靜態類的forName(字符串 的className)拋出 ClassNotFoundException的

  • 公共靜態類的forName(字符串 名,布爾初始化,類加載器 裝載機)拋出的ClassNotFoundException

  • 的ClassLoader

    公共類的loadClass(字符串 名)拋出的ClassNotFoundException { 回報的loadClass(姓名,假); }

已知的是在的forName方法,我們可以指定初始化的標誌是,這將跳過某些該類被初始化靜態的東西。但是還有什麼? 我應該如何正確使用它們?

最好你可以展示一些很好的例子。

謝謝!

UPDATE:

提出的問題後,我做了一些簡單的類加載器的測試。

ClassLoader cls = ClassLoader.getSystemClassLoader(); 
     Class someClass = cls.loadClass("Test");   
     Class someClass0= Class.forName("Test");   
     Class someClass1= Class.forName("Test",false,cls); 


     URL[] urls = new URL[] {new File("bin/").toURL()}; 
     ClassLoader cls2 = new URLClassLoader(urls, null); 
     Class someClass2 = cls2.loadClass("Test");   

     ClassLoader cls3 = new URLClassLoader(urls, cls); 
     Class someClass3 = cls3.loadClass("Test");   

     System.out.println(someClass.equals(someClass0));  
     System.out.println(someClass.equals(someClass1)); 
     System.out.println(someClass.equals(someClass2)); 
     System.out.println(someClass.equals(someClass3)); 

結果是

真,真,假,真

UPDATE

這是我約
Difference between loadClass(String name) and loadClass(String name, boolean resolve)

+0

@Bohemian我已閱讀的鏈接,我沒有看到任何人強調說的Class.forName將初始化靜態的東西還包括靜態塊和靜態變量的區別。另外這兩個方法實際上終於調用了不同的本地方法,private native void esolveClass0(Class c);私有靜態本地Class forName0(字符串名稱,布爾初始化,ClassLoader加載器)拋出ClassNotFoundException;它會導致差異嗎? –

回答

9

考慮以下代碼

class X 
{ 
    static{ System.out.println("init class X..."); } 

    int foo(){ return 1; } 

    Y bar(){ return new Y(); } 
} 

最基本的API是ClassLoader.loadClass(String name, boolean resolve)

Class classX = classLoader.loadClass("X", resolve); 

如果resolve是真實的,它也將嘗試加載由X引用的所有類。在這種情況下,Y也將被加載。如果resolve爲false,則此時將不加載Y

似乎沒有任何理由resolve=true。如果沒有人呼叫X.bar(),則永遠不需要Y,爲什麼我們現在應該加載它?如果Y丟失或損壞,我們會嘗試加載X出錯,這是完全不必要的。

有趣的是,這種方法是protected,所以調用它並不容易。

另一種方法loadClass(name)只需調用loadClass(name,false)。它是公開的,它需要resolve=false的明智選擇。所以這正是開發人員所需要的。

ClassLoader只加載類,它不初始化類。我們可以檢查課程元數據,例如其超類,其註釋,方法和字段等,而不觸發靜態初始化執行。這個事實對於框架非常重要。

現在,Class.forName

基本上,Class.forName(String name, boolean initialize, ClassLoader loader)電話loader.loadClass(name)。如果initialize=true,該類已初始化 - 在X示例中,我們將看到"init class X..."已打印。

Class.forName(name)forName(name, true, currentLoader)相同。

現在,爲什麼有人想在這一點上初始化類?如果班級只在必要時才初始化,會不會更好?一個着名的用例是JDBC初始化:

Class.forName("com.mysql.jdbc.Driver"); 

約定是,JDBC驅動程序類在其靜態初始化程序中註冊自己。上述代碼將觸發靜態初始化,使驅動程序可供後續使用。

從今天的角度來看,這種設計非常奇怪。我們通常不依賴於靜態初始化器。所以initialize=true沒有太大的理由,應該避免Class.forName(name)

A 「類文本」 將返回類,沒有初始化它

Class c = com.mysql.jdbc.Driver.class; 
    // actually compiled to 
    Class c = Class.forName("com.mysql.jdbc.Driver", false, currentLoader); 

現在,到底是什麼在 「currentLoader」?這是當前類

class A 
{ 
    void foo() 
    { 
     currenLoader == THIS_A_CLASS.getClassLoader() 
    } 
} 

X.bar()調用首次的類加載器,需要一個「Y」類。發生了什麼事大致是

class X 
    bar() 
     // new Y(); 

     Class classY = currentLoader.loadClass("Y"); 
     Constructor cst = classY.getConstructor(); 

     // next line will initialize Y (if not yet) 
     // creating an instance of a class requires it be initialized 
     Object y = cst.newInstance(); 
+0

令人驚歎的答案。太糟糕了,這個問題被標記爲重複。 –

1

ClassLoader.loadClass(字符串名稱回答)將嘗試使用speci加載類fied類加載器。 Class.forName(String name)將嘗試使用默認系統類加載器層次結構加載該類。

相關問題