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

Java 反射機制核心 API 深度解析與實戰應用模式

     編輯:Java 相關知識

Java 反射全景指南:從 Class 對象到動態代理、框架級應用模式

反射是 Java 動態性的基石,支撐 Spring IOC、MyBatis 映射、Jackson 序列化等所有主流框架。本文系統梳理核心 API、訪問控制繞過、性能優化、實戰模式。

核心類層級結構

java.lang.Class           // 入口:類元數據
    getFields() / getDeclaredFields()        // Field[]
    getMethods() / getDeclaredMethods()      // Method[]
    getConstructors() / getDeclaredConstructors() // Constructor[]
    getSuperclass() / getInterfaces()        // 繼承關係
    getAnnotations() / getDeclaredAnnotations() // 註解
    newInstance() / getDeclaredConstructor().newInstance() // 實例化

java.lang.reflect.Field      // 字段操作
    getType() / getGenericType()
    get(Object) / set(Object, Object)        // 讀寫值
    setAccessible(true)                      // 繞過 private

java.lang.reflect.Method     // 方法操作
    getParameterTypes() / getGenericParameterTypes()
    getReturnType() / getGenericReturnType()
    getExceptionTypes()
    invoke(Object, Object...)                // 動態調用
    setAccessible(true)

java.lang.reflect.Constructor // 構造器操作
    newInstance(Object...)                   // 創建實例
    setAccessible(true)

訪問控制繞過:setAccessible(true) 原理與風險

Field f = Target.class.getDeclaredField("secret");
f.setAccessible(true); // 關閉訪問檢查
Object value = f.get(targetInstance);

// JDK 9+ 模塊系統限制:需在 module-info.java 開放
// module my.app { opens com.my.internal to java.base; }
// 或啟動參數 --add-opens java.base/java.lang=ALL-UNNAMED

風險:破壞封裝、繞過安全管理器、JDK 17+ 默認強封裝需額外配置。

實戰應用模式

1. 通用 Bean 複制 / 映射工具

public static void copyProperties(Object source, Object target) {
    Map targetFields = Arrays.stream(target.getClass().getDeclaredFields())
        .collect(Collectors.toMap(Field::getName, f -> { f.setAccessible(true); return f; }));
    
    for (Field sf : source.getClass().getDeclaredFields()) {
        sf.setAccessible(true);
        Field tf = targetFields.get(sf.getName());
        if (tf != null && tf.getType().isAssignableFrom(sf.getType())) {
            tf.set(target, sf.get(source));
        }
    }
}

2. 註解驅動配置綁定

@Retention(RUNTIME) @Target(FIELD)
public @interface ConfigValue { String key() default ""; }

public static void bindConfig(Object bean, ConfigSource source) {
    for (Field f : bean.getClass().getDeclaredFields()) {
        ConfigValue ann = f.getAnnotation(ConfigValue.class);
        if (ann != null) {
            f.setAccessible(true);
            String key = ann.key().isEmpty() ? f.getName() : ann.key();
            String val = source.getProperty(key);
            if (val != null) convertAndSet(f, bean, val); // 類型轉換
        }
    }
}

3. 動態代理實現 AOP

public class LoggingProxy implements InvocationHandler {
    private final Object target;
    
    public static Object newInstance(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new LoggingProxy(target));
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.nanoTime();
        try {
            return method.invoke(target, args);
        } finally {
            log.info("{}#{} took {} ms", target.getClass().getSimpleName(), 
                method.getName(), (System.nanoTime() - start) / 1e6);
        }
    }
}

4. 類型安全的反射工具封裝

public class Reflect {
    private final Class clazz;
    
    public static Reflect on(Class clazz) { return new Reflect(clazz); }
    public static Reflect on(String className) { 
        try { return on(Class.forName(className)); } 
        catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); }
    }
    
    public Reflect create(Object... args) {
        try {
            Constructor c = Arrays.stream(clazz.getDeclaredConstructors())
                .filter(cn -> cn.getParameterCount() == args.length)
                .findFirst().orElseThrow(() -> new IllegalStateException("No matching constructor"));
            c.setAccessible(true);
            this.instance = c.newInstance(args);
            return this;
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    
    public Reflect set(String fieldName, Object value) {
        try {
            Field f = clazz.getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(instance, value);
            return this;
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    
    public  T call(String methodName, Object... args) {
        try {
            Method m = Arrays.stream(clazz.getDeclaredMethods())
                .filter(mn -> mn.getName().equals(methodName) && mn.getParameterCount() == args.length)
                .findFirst().orElseThrow(() -> new IllegalStateException("No matching method"));
            m.setAccessible(true);
            return (T) m.invoke(instance, args);
        } catch (Exception e) { throw new RuntimeException(e); }
    }
    
    public Object get() { return instance; }
    private Object instance;
}

// 使用
User user = Reflect.on(User.class).create().set("name", "Tom").set("age", 18).call("init").get();

性能優化策略

策略原理適用場景
緩存 Member 對象Field/Method/Constructor 對象創建昂貴,靜態緩存復用高頻調用路徑
MethodHandle (JDK 7+)直接方法句柄,JIT 內聯優化優於 reflect熱點路徑、框架開發
VarHandle (JDK 9+)字段/數組元素訪問句柄,支援原子操作並發容器、非阻塞算法
字節碼生成 (ASM/ByteBuddy)運行時生成專用類,消除反射開銷極致性能、ORM、序列化
避免 setAccessible破壞 JIT 優化假設,模塊系統限制優先設計 public API

MethodHandle 遷移示例

// 反射調用
Method m = Service.class.getMethod("process", Request.class);
m.invoke(service, request);

// MethodHandle 等效
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class, Request.class);
MethodHandle mh = lookup.findVirtual(Service.class, "process", mt);
mh.invokeExact(service, request); // 簽名精確匹配,性能更優
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved