Class.forName()


在一些應用中,無法事先知道使用者將載入什麼類別(例如載入JDBC驅動程式),而必須讓使用者指定類別名稱以載入類別。你可以使用Class的靜態forName()方法實現動態加載類別,以下是個簡單示範,可以指定類別名稱來獲得類別的相關資訊:
     try {
        Class c = Class.forName(args[0]);
        System.out.println("類別名稱:" + c.getName());
        System.out.println("是否為介面:" + c.isInterface());
        System.out.println("是否為基本型態:" + c.isPrimitive());
        System.out.println("是否為陣列:" + c.isArray());
        System.out.println("父類別:" + c.getSuperclass().getName());
     }
     catch(ArrayIndexOutOfBoundsException e) {
        System.out.println("沒有指定類別名稱");
     }
     catch(ClassNotFoundException e) {
         System.out.println("找不到指定的類別");
     }

在 指定類別給forName()方法後,如果找不到指定的類別,會丟出ClassNotFoundException例外。Class的靜態forName ()方法有兩個版本,另一個版本可以讓您指定類別名稱、載入類別時是否執行靜態區塊、指定類別載入器(Class loader):
static Class forName(String name, boolean initialize, ClassLoader loader)

之前曾經說過,預設上在載入類別的時候,如果類別中有定義靜態區塊則會執行它,你可以使用forName()的第二個版本,將initialize設定為false,如此在載入類別時並不會馬上執行靜態區塊,而會在使用類別建立物件時才執行靜態區塊,為了印證,你可以先設計一個測試類別。
package cc.openhome;
public class Some {

    static {
        System.out.println("[執行靜態區塊]");
    }
}

範例只定義了靜態區塊顯示一段訊息,以觀察靜態區塊何時被執行,如果用第一個版本的forName()方法:
    try {
        System.out.println("載入cc.openhome.Some");
        Class c = Class.forName("cc.openhome.Some");

        System.out.println("使用cc.openhome.Some宣告參考名稱");
        Some test = null;

        System.out.println("使用cc.openhome.Some建 立物件");                        
        test = new Some();
    }
    catch(ClassNotFoundException e) {
        System.out.println("找不到指定的類別");
    }

從執行結果中你會看到,第一個版本的forName()方法在載入類別之後,預設會馬上執行靜態區塊。如果用第二個版本的forName()方法:
    try {
        System.out.println("載入cc.openhome.Some");
        Class c = Class.forName("cc.openhome.Some",
                     false, // 載入類別時不執行靜態方法
                     Thread.currentThread().getContextClassLoader());

        System.out.println("使用cc.openhome.Some宣告參考名稱");
        Some test = null;

        System.out.println("使用cc.openhome.Some建 立物件");                        
        test = new Some();
    }
    catch(ClassNotFoundException e) {
        System.out.println("找不到指定的類別");
    }

由 於使用第二個版本的forName()方法時,設定initialize為false,所以載入類別時並不會馬上執行靜態區塊,而會在使用類別建立物件時 才去執行靜態區塊,第二個版本的forName()方法會需要一個 類別載入器(Class loader),範例中所使用的是主執行緒的環境類別載入器(Context Class Loader)。

事實上如果使用第一個版本的forName()方法,等同於:
Class.forName(className, true, currentLoader);

其中currentLoader是目前類別的類別載入器,也就是如果你在A類別中使用Class.forName()第一個版本,預設就是用A類別的類別載入器來載入類別。