Java 反射機制允許程式在執行期動態獲取類資訊、建立實例、呼叫方法,是 Spring、Hibernate 等主流框架的核心基石。本文透過一個完整可執行的範例,詳細演示如何使用反射 API 動態呼叫帶參數的方法,並解析關鍵步驟與常見陷阱。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflexTest {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, InstantiationException {
// 1. 定義目標方法的參數型別陣列(對應 Demo.getSome(String, Integer, String))
Class>[] paramTypes = new Class[3];
paramTypes[0] = String.class;
paramTypes[1] = Integer.class;
paramTypes[2] = String.class;
// 2. 獲取目標方法物件:類.getDeclaredMethod(方法名, 參數型別...)
Method method = Demo.class.getDeclaredMethod("getSome", paramTypes);
// 3. 準備實際參數值陣列(順序、型別必須與 paramTypes 完全對應)
Object[] argsValues = new Object[3];
argsValues[0] = "pp"; // String
argsValues[1] = 4; // Integer (自動裝箱)
argsValues[2] = "3"; // String
// 4. 動態呼叫方法:method.invoke(實例物件, 參數陣列)
// 此處 Demo.class.newInstance() 等同於 new Demo(),需無參建構子
method.invoke(Demo.class.newInstance(), argsValues);
}
}
// 目標類別
class Demo {
public void getSome(String name, Integer year, String age) {
System.out.println("name is :" + name + "; age is :" + age + "; year is :" + year);
}
}
getMethod(String name, Class>... parameterTypes):僅能獲取 public 方法(含繼承)。getDeclaredMethod(String name, Class>... parameterTypes):可獲取類自行宣告的所有方法(含 private/protected),但不含繼承方法。範例使用此方式更通用。paramTypes 必須與目標方法簽名完全一致:
Xxx.TYPE(如 int.class / Integer.TYPE)Xxx.classNoSuchMethodExceptionObject invoke(Object obj, Object... args)
obj:方法接收者。靜態方法傳 null,實例方法傳實例物件。args:可變長參數陣列,自動處理基本型別裝箱/拆箱。反射呼叫會拋出多種受檢異常,建議採用「捕獲轉換」策略:
try {
method.invoke(instance, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// InvocationTargetException 內部包裹了目標方法真實拋出的異常
Throwable cause = e.getCause();
throw new RuntimeException("反射呼叫失敗: " + cause.getMessage(), cause);
}
Method 物件或使用 MethodHandle/VarHandle。method.setAccessible(true),但在 Java 9+ 模組化系統下可能受限,需在 module-info.java 中 opens 相關套件。