Java 反射允許運行時動態獲取類信息並調用方法,打破了編譯期綁定的限制。本文通過實例演示如何使用反射調用 Math.sin()(靜態方法)和 String.equals()(非靜態方法),並解析核心 API 與常見坑點。
| 類/方法 | 用途 |
|---|---|
Class.forName("全限定名") | 加載類對象 |
clazz.getDeclaredMethod(name, paramTypes) | 獲取聲明的方法(含 private) |
clazz.getMethod(name, paramTypes) | 獲取 public 方法(含繼承) |
method.invoke(obj, args) | 調用方法,靜態方法 obj 為 null |
method.setAccessible(true) | 暴力反射,繞過訪問修飾符檢查 |
import java.lang.reflect.Method;
public class DynamicInvocationDemo {
public static void main(String[] args) {
try {
// ========== 1. 調用靜態方法:Math.sin(double) ==========
System.out.println("=== 調用 Math.sin() 靜態方法 ===");
// 獲取 Method 對象:參數類型用 Double.TYPE 表示 double 基本類型
Method sinMethod = Math.class.getDeclaredMethod("sin", double.class);
// 靜態方法調用:第一個參數傳 null(無實例)
Double result = (Double) sinMethod.invoke(null, 1.0); // 也可傳 1,自動裝箱
System.out.printf("sin(1.0) = %.4f%n", result); // 輸出: 0.8415
// ========== 2. 調用非靜態方法:String.equals(Object) ==========
System.out.println("\n=== 調用 String.equals() 實例方法 ===");
Method equalsMethod = String.class.getDeclaredMethod("equals", Object.class);
String target = "明日科技";
String instance = new String("明日科技"); // 新對象,非字面量
// 非靜態方法調用:第一個參數為調用實例
Boolean equal = (Boolean) equalsMethod.invoke(instance, target);
System.out.println("字符串比較結果:" + equal); // true
// ========== 3. 進階:調用私有方法 ==========
System.out.println("\n=== 反射調用私有方法演示 ===");
invokePrivateMethod();
} catch (Exception e) {
e.printStackTrace();
}
}
/** 定義一個包含私有方法的測試類 */
static class Service {
private String secret(String prefix, int id) {
return prefix + "-SECRET-" + id;
}
}
private static void invokePrivateMethod() throws Exception {
Service service = new Service();
Class> clazz = service.getClass();
// 獲取私有方法
Method secretMethod = clazz.getDeclaredMethod("secret", String.class, int.class);
// 關鍵:暴力反射打破封裝
secretMethod.setAccessible(true);
// 調用
String result = (String) secretMethod.invoke(service, "TOKEN", 100);
System.out.println("私有方法返回:" + result); // TOKEN-SECRET-100
}
}
int.class / Integer.TYPE、double.class / Double.TYPE 等String.class、Object.class、List.class 等int[].class、String[].class// 靜態方法
method.invoke(null, args...); // 第一參數忽略,傳 null
// 實例方法
method.invoke(instance, args...); // 第一參數必須是目標對象實例
invoke() 拋出的 InvocationTargetException 包裝了真實異常,需通過 e.getCause() 獲取:
try {
method.invoke(obj, args);
} catch (InvocationTargetException e) {
Throwable realCause = e.getCause(); // 真實業務異常
// 處理 realCause...
}
Method 對象MethodHandle、JDK 8+ VarHandle 性能更優setAccessible(true) 破壞封裝,可能導致安全漏洞,生產環境謹慎使用opens 包Method 對象避免重複 getDeclaredMethod 開銷反射是 Java 動態性的基石,掌握 Class → Method → invoke 鏈路是核心。本文示範了靜態/實例、公有/私有方法的調用全流程,理解參數類型表示、異常解包、性能權衡,即可在框架開發、工具構建中靈活運用。