首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 反射機制深度解析:從 Class 載入到動態呼叫的完整實戰指南

     編輯:Java 綜合教學

什麼是反射?

反射是 Java 語言在執行期檢查、修改類別結構與行為的能力。編譯期僅有 .class 位元碼,執行期 JVM 將其載入為 java.lang.Class 物件,反射 API 即操作此元資料物件,實現:

  • 反編譯:.class → .java 結構還原
  • 動態存取:屬性、方法、建構子、註解
  • 框架核心:Spring IOC/DI、MyBatis Mapper 掃描、Hibernate 實體映射、JUnit 測試引擎

核心 API 速查表

類別用途常用方法
java.lang.Class類別元資料入口forName(), getFields(), getMethods(), getConstructors(), newInstance()
java.lang.reflect.Constructor建構子操作newInstance(), setAccessible(true)
java.lang.reflect.Field屬性操作get(obj), set(obj, val), getModifiers()
java.lang.reflect.Method方法操作invoke(obj, args), getParameterTypes()
java.lang.reflect.Modifier修飾符解析isPublic(), isStatic(), toString(mod)

取得 Class 物件的三種方式

public class Employee {
    private String name;
    public Employee() {}
    public Employee(String name) { this.name = name; }
    public void work() { System.out.println(name + " 在工作"); }
}

// 方式 1:Class.forName("全類名") — 最常用,支援動態類名
Class c1 = Class.forName("Employee");

// 方式 2:類字面常量 — 編譯期已知類型,效能最佳
Class c2 = Employee.class;

// 方式 3:實例.getClass() — 執行期類型(多型場景)
Employee e = new Employee();
Class c3 = e.getClass();

// 驗證:同一 JVM 中同一類只有一個 Class 物件
System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true

類載入時機差異

class A {
    static { System.out.println("A 初始化"); }
}

// Class.forName("A")  → 觸發靜態區塊(主動使用)
// A.class             → 不觸發(被動引用)
// new A()             → 觸發

實戰:反射建立物件、存取私有欄位、呼叫方法

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("Employee");

        // 1. 調用有參建構子
        Constructor ctor = clazz.getDeclaredConstructor(String.class);
        Employee emp = (Employee) ctor.newInstance("張三");

        // 2. 存取私有欄位
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true); // 破壞封裝
        System.out.println("原名:" + nameField.get(emp)); // 張三
        nameField.set(emp, "李四");
        System.out.println("新名:" + nameField.get(emp)); // 李四

        // 3. 呼叫方法
        Method work = clazz.getMethod("work");
        work.invoke(emp); // 輸出:李四 在工作
    }
}

效能與安全考量

  • 效能:反射比直接呼叫慢 10~100 倍(JIT 難優化、存取檢查、自動裝箱)。熱點路徑請快取 Method/Field/Constructor 物件,或用 MethodHandle (Java 7+) / VarHandle (Java 9+)。
  • 安全:setAccessible(true) 受 SecurityManager 限制;模組化 (Java 9+) 需 opens package to module 或命令行 --add-opens。
  • 封裝破壞:僅框架層使用,業務代碼嚴禁濫用。

進階應用場景

  1. 註解驅動開發:掃描 @Controller、@Autowired、@Transactional 實現 AOP
  2. 動態代理:Proxy.newProxyInstance() + InvocationHandler (Spring AOP 底層)
  3. 泛型型別擷取:TypeToken (Gson) / ParameterizedType 解決類型擦除
  4. 服務發現:SPI 機制 (ServiceLoader) 載入實作類

總結

反射是 Java 動態特性的基石,賦予框架「約定優於配置」的魔力。理解 Class 載入時機、三大核心元件 (Field/Method/Constructor) 協作、setAccessible 邊界,是進階 Java 工程師的必修課。實務上:框架寫反射,業務用框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved