反射允許程式在執行期檢查類別結構、動態建立實例、呼叫方法、存取欄位,是框架(Spring、Hibernate、MyBatis)實現解耦與自動裝配的基石。本文透過完整範例展示反射常用操作。
package reflection;
public class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name; this.age = age;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public void sayHello() { System.out.println("Hi, " + name); }
}
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionGuide {
public static void main(String[] args) throws Exception {
Class<User> clazz = User.class; // 方式一:類字面常數
// Class> clazz = Class.forName("reflection.User"); // 方式二:字串載入
// 1. 列出所有宣告的欄位(含 private)
System.out.println("=== Fields ===");
for (Field f : clazz.getDeclaredFields()) {
System.out.println(f.getName() + " : " + f.getType().getSimpleName());
}
// 2. 列出所有宣告的方法
System.out.println("\n=== Methods ===");
for (Method m : clazz.getDeclaredMethods()) {
System.out.println(m.getName() + " : " + m.getReturnType().getSimpleName());
}
// 3. 取得建構子並實例化
Constructor<User> ctor = clazz.getDeclaredConstructor(String.class, int.class);
User user = ctor.newInstance("Alice", 25);
// 4. 存取 private 欄位(需 setAccessible)
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
System.out.println("\n原始 name: " + nameField.get(user));
nameField.set(user, "Bob");
System.out.println("修改後 name: " + nameField.get(user));
// 5. 呼叫方法
Method sayHello = clazz.getDeclaredMethod("sayHello");
sayHello.invoke(user); // 輸出: Hi, Bob
// 6. 呼叫 setter/getter
Method setAge = clazz.getMethod("setAge", int.class);
setAge.invoke(user, 30);
Method getAge = clazz.getMethod("getAge");
System.out.println("年齡: " + getAge.invoke(user));
}
}
| 需求 | API | 備註 |
|---|---|---|
| 載入類別 | Class.forName("全限定名") | 會觸發靜態初始化 |
| 取得 public 建構子 | clazz.getConstructor(參數型別...) | 拋 NoSuchMethodException |
| 取得任意建構子 | clazz.getDeclaredConstructor(參數型別...) | 需 setAccessible(true) |
| 建立實例 | constructor.newInstance(引數...) | 自動處理拋出的異常 |
| 取得 public 方法 | clazz.getMethod(名稱, 參數型別...) | 搜尋父類別 |
| 取得任意方法 | clazz.getDeclaredMethod(名稱, 參數型別...) | 僅本類別,需 setAccessible |
| 呼叫方法 | method.invoke(實例, 引數...) | static 方法實例傳 null |
| 存取 public 欄位 | clazz.getField(名稱) | 搜尋父類別 |
| 存取任意欄位 | clazz.getDeclaredField(名稱) | 需 setAccessible(true) |