在一些應用中,無法事先知道使用者將載入什麼類別(例如載入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("[執行靜態區塊]");
}
}
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類別的類別載入器來載入類別。