在 Java 開發中,Class.forName() 讓我們能根據配置文件動態載入類,這對於「面向介面編程」極其重要。以資料庫連線池為例,我們定義好介面,提供多種實現類,使用者只需修改配置檔即可切換實現,原始碼完全不用動。但現實往往更複雜:許多單例類將建構子設為 private,只暴露靜態 getInstance() 方法取得實例。此時單純用 Class.forName().newInstance() 就失效了——因為根本無法直接實例化。
Java 反射(Reflection)提供了完整的運行時類結構探測能力。雖然比 PHP 的 eval() 繁瑣,但它能完成幾乎所有運行時決定的動作。下面通過完整範例示範如何動態呼叫靜態工廠方法。
import java.lang.reflect.*;
public class MyTestClass {
private static final Object LOCK = new Object();
private static MyTestClass instance = null;
private String configName = "";
private boolean isFromResource = true;
public static Object getInstance(String configName, Boolean isFromResource) {
synchronized (LOCK) {
if (instance == null) {
instance = new MyTestClass(configName, isFromResource);
}
}
return instance;
}
private MyTestClass(String configName, Boolean isFromResource) {
this.configName = configName;
this.isFromResource = isFromResource.booleanValue();
}
public void echoInfo() {
System.out.println("current arguments : configName=[" + configName + "], isFromResource=[" + isFromResource + "]");
}
public static void main(String[] args) throws Exception {
// 1. 定義目標方法的參數型別
Class>[] parameterTypes = { String.class, Boolean.class };
// 2. 取得類物件與目標 Method
String className = "MyTestClass";
Class> clazz = Class.forName(className);
Method getInstanceMethod = null;
try {
getInstanceMethod = clazz.getMethod("getInstance", parameterTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 3. 呼叫靜態方法並使用回傳實例
if (getInstanceMethod != null) {
MyTestClass obj = (MyTestClass) getInstanceMethod.invoke(
null, // 靜態方法無需實例,傳 null
new Object[] { "src/myconfig.properties", Boolean.FALSE }
);
obj.echoInfo();
} else {
throw new Exception("初始化失敗:找不到 getInstance(String, Boolean) 方法");
}
}
}
Class>[] parameterTypes = { String.class, Boolean.class };
對應目標方法 getInstance(String, Boolean) 的簽名。注意要用 Boolean.class 而非 boolean.class,因為原始碼用的是包裝類型。
clazz.getMethod("getInstance", parameterTypes) 會回傳 public 的靜態方法。若方法不存在會拋出 NoSuchMethodException。
method.invoke(null, args):
null 表示呼叫靜態方法(非靜態則傳實例)Object[],依序對應方法參數Boolean vs boolean、Integer vs int 會導致 NoSuchMethodExceptionpublic,需用 getDeclaredMethod 並呼叫 setAccessible(true)Method 物件module-info.java 開放 opens 才能反射私有成員掌握反射動態調用靜態方法,能讓你的框架級代碼更靈活、更符合「開閉原則」。