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

Java 反射機制深度解析:動態創建、屬性訪問、對象拷貝實戰

     編輯:Java 相關知識

運行時檢查類結構、實例化對象、繞過封裝的核心技術

反射是框架(Spring、Hibernate、MyBatis、Jackson)的基石。核心類:Class<T>(類元數據)、Field(字段)、Method(方法)、Constructor<T>(構造器)、Modifier(修飾符)。本文通過 Person 類演示:獲取類信息、動態實例化、屬性讀寫、對象深拷貝。

核心 API 速查

任務API示例
獲取 ClassClass.forName()、.class、obj.getClass()Class<?> c = Class.forName("pkg.Person")
獲取所有字段c.getDeclaredFields()(含私有)Field[] fs = c.getDeclaredFields()
獲取所有方法c.getDeclaredMethods()Method[] ms = c.getDeclaredMethods()
暴力訪問私有field.setAccessible(true)繞過封裝,框架常用
調用無參構造器c.getDeclaredConstructor().newInstance()需處理 5 種異常
調用方法method.invoke(obj, args)靜態方法傳 null 作為 obj
讀寫字段field.get(obj) / field.set(obj, val)需 setAccessible(true)

實戰 1:獲取類結構信息

public static void inspectClass(String className) {
    try {
        Class<?> c = Class.forName(className);
        System.out.println("類名:" + c.getName());
        System.out.println("簡單名:" + c.getSimpleName());
        System.out.println("包名:" + c.getPackageName());
        System.out.println("修飾符:" + Modifier.toString(c.getModifiers()));
        System.out.println("父類:" + c.getSuperclass());
        System.out.println("介面:" + Arrays.toString(c.getInterfaces()));
        System.out.println("--- 字段 ---");
        for (Field f : c.getDeclaredFields()) {
            System.out.printf("  %s %s %s%n", 
                Modifier.toString(f.getModifiers()), f.getType().getSimpleName(), f.getName());
        }
        System.out.println("--- 方法 ---");
        for (Method m : c.getDeclaredMethods()) {
            System.out.printf("  %s %s %s(%s)%n",
                Modifier.toString(m.getModifiers()), m.getReturnType().getSimpleName(),
                m.getName(), Arrays.toString(m.getParameterTypes()));
        }
    } catch (ClassNotFoundException e) { e.printStackTrace(); }
}

實戰 2:通用對象深拷貝(基於 JavaBean 慣例)

@SuppressWarnings("unchecked")
public static <T> T deepCopy(T source) throws Exception {
    if (source == null) return null;
    Class<?> clazz = source.getClass();
    // 1. 創建目標實例(無參構造器)
    T target = (T) clazz.getDeclaredConstructor().newInstance();
    // 2. 遍歷所有字段
    for (Field field : clazz.getDeclaredFields()) {
        field.setAccessible(true); // 訪問私有
        Object value = field.get(source);
        // 3. 遞歸拷貝非基本型別、非不可變類、非集合/Map(簡化版)
        if (value != null && !isPrimitiveOrWrapper(field.getType()) 
                && !field.getType().isArray()) {
            value = deepCopy(value); // 遞歸
        }
        // 數組處理略
        field.set(target, value);
    }
    return target;
}

private static boolean isPrimitiveOrWrapper(Class<?> c) {
    return c.isPrimitive() || c == String.class || Number.class.isAssignableFrom(c) 
        || c == Boolean.class || c == Character.class || c.isEnum();
}

生產建議:直接用 BeanUtils.copyProperties()(Spring/Apache Commons)、MapStruct(編譯期生成)、Dozer、Jackson 序列化反序列化,勿手寫。

效能與安全考量

  • 效能:反射比直接調用慢 10-100 倍(JIT 難優化、訪問檢查、裝箱拆箱)。熱路徑請緩存 Field/Method/Constructor 對象,或用 MethodHandle(Java 7+)、VarHandle(Java 9+)。
  • 安全:setAccessible(true) 受 SecurityManager 限制(模塊化 JDK 9+ 需 --add-opens)。
  • 模塊化:JDK 9+ 強封裝,內部 API 需 opens pkg to module 或命令行 --add-opens。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved