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

深入理解 Java 反射:Class 對象、類型檢查、反射 API 與動態代理實戰

     編輯:Java 綜合教學

兩種運行時類型識別方式

  • RTTI (Run-Time Type Identification):編譯期已知類型,通過類型轉換、instanceof、Class 字面量 (MyClass.class) 識別。
  • 反射:編譯期未知類型,運行時通過 Class.forName() 載入 .class 文件,動態發現並操作類的結構(欄位、方法、構造器)。

Class 對象與類加載

// 獲取 Class 對象的三種方式
Class c1 = MyClass.class;           // 不觸發初始化
Class c2 = obj.getClass();          // 運行時類型
Class c3 = Class.forName("pkg.MyClass"); // 觸發初始化(靜態塊、靜態欄位)

類加載三階段:載入 (尋找 .class → 生成 Class 對象) → 鏈接 (驗證、準備靜態欄位) → 初始化 (執行靜態初始化器、靜態塊)。

反射核心 API

類別代表常用操作
Class類/介面/陣列/基本型別/voidgetFields/getMethods/getConstructors/getDeclaredFields/forName/newInstance
Field成員變數get/set、setAccessible(true) 訪問 private
Method成員方法invoke(obj, args)、getParameterTypes、getReturnType
Constructor構造器newInstance(args)、getParameterTypes

反射實戰:通用對象屬性拷貝

public static void copyProperties(Object src, Object dest) throws Exception {
    Class clazz = src.getClass();
    for (Field f : clazz.getDeclaredFields()) {
        f.setAccessible(true);
        String name = f.getName();
        PropertyDescriptor pd = new PropertyDescriptor(name, clazz);
        Method getter = pd.getReadMethod();
        Method setter = pd.getWriteMethod();
        if (getter != null && setter != null) {
            Object value = getter.invoke(src);
            setter.invoke(dest, value);
        }
    }
}

動態代理:JDK Proxy 實戰

核心組件

  • InvocationHandler:攔截所有代理方法調用,統一分派邏輯。
  • Proxy.newProxyInstance(classLoader, interfaces, handler):生成實現指定介面的代理類實例。

完整範例

interface Service { void doWork(String msg); }

class RealService implements Service {
    public void doWork(String msg) { System.out.println("Real: " + msg); }
}

class LoggingHandler implements InvocationHandler {
    private final Object target;
    public LoggingHandler(Object target) { this.target = target; }
    @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[LOG] before " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("[LOG] after " + method.getName());
        return result;
    }
}

public class ProxyDemo {
    public static void main(String[] args) {
        Service real = new RealService();
        Service proxy = (Service) Proxy.newProxyInstance(
                Service.class.getClassLoader(),
                new Class[]{Service.class},
                new LoggingHandler(real));
        proxy.doWork("Hello");  // 輸出 LOG → Real → LOG
    }
}

反射 vs RTTI 本質差異

RTTI:編譯器開啟並檢查 .class 文件。
反射:運行時開啟並檢查 .class 文件。

效能與安全考量

  • 反射比直接調用慢(存取檢查、動態解析),熱點路徑可用 MethodHandle / VarHandle 或緩存 Method/Field 對象優化。
  • setAccessible(true) 破壞封裝,需謹慎使用;模組化 (JPMS) 可能限制深度反射。
  • 序列化、Spring IOC、Hibernate、動態代理、註解處理器等框架大量依賴反射。

總結

反射賦予 Java「運行時自我認知與操作」的能力,是框架開發的基石。掌握 Class 載用機制、核心 API、動態代理模式,並理解其效能代價與安全邊界,是進階 Java 工程師的必修課。

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