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

Java 反射遍歷實體屬性、賦值與取值完整工具類

     編輯:Java 相關知識

反射核心 API 速查

類別常用方法用途
ClassgetDeclaredFields()、getMethods()、getConstructors()、newInstance()獲取類別結構、創建實例
FieldgetName()、getType()、setAccessible(true)、set(obj, val)、get(obj)操作成員變數(含 private)
MethodgetName()、getReturnType()、getParameterTypes()、invoke(obj, args)呼叫方法(含 private)

通用反射工具類實現

public class ReflectionUtils {

    /** 獲取所有欄位名與型別 */
    public static List<FieldInfo> getFieldInfos(Object obj) {
        List<FieldInfo> list = new ArrayList<>();
        for (Field f : obj.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            list.add(new FieldInfo(f.getName(), f.getType(), f));
        }
        return list;
    }

    /** 設值:支援基本型別、String、Date、包裝型別自動轉換 */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        try {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            // 型別適配:字串轉目標型別
            Object converted = convertValue(value, f.getType());
            f.set(obj, converted);
        } catch (Exception e) {
            throw new RuntimeException("設值失敗: " + fieldName, e);
        }
    }

    /** 取值 */
    public static Object getFieldValue(Object obj, String fieldName) {
        try {
            Field f = obj.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            return f.get(obj);
        } catch (Exception e) {
            throw new RuntimeException("取值失敗: " + fieldName, e);
        }
    }

    /** 呼叫 Getter */
    public static Object invokeGetter(Object obj, String fieldName) {
        String getter = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
        try {
            Method m = obj.getClass().getMethod(getter);
            return m.invoke(obj);
        } catch (Exception e) {
            throw new RuntimeException("Getter 呼叫失敗: " + getter, e);
        }
    }

    /** 字串自動轉換為目標型別 */
    private static Object convertValue(Object value, Class<?> targetType) {
        if (value == null) return null;
        if (targetType.isInstance(value)) return value;
        if (targetType == String.class) return value.toString();
        if (targetType == int.class || targetType == Integer.class) return Integer.valueOf(value.toString());
        if (targetType == long.class || targetType == Long.class) return Long.valueOf(value.toString());
        if (targetType == double.class || targetType == Double.class) return Double.valueOf(value.toString());
        if (targetType == boolean.class || targetType == Boolean.class) return Boolean.valueOf(value.toString());
        if (targetType == Date.class) {
            // 可擴充支援多種日期格式
            return new Date(Long.valueOf(value.toString()));
        }
        throw new IllegalArgumentException("不支援的型別: " + targetType);
    }

    static class FieldInfo {
        String name; Class<?> type; Field field;
        FieldInfo(String n, Class<?> t, Field f) { name=n; type=t; field=f; }
    }
}

使用範例

public class User {
    private String name;
    private int age;
    private Date birthday;
    // getter/setter 省略
}

public class Test {
    public static void main(String[] args) {
        User u = new User();
        
        // 批次設值
        Map<String, Object> data = Map.of(
            "name", "張三",
            "age", "25",
            "birthday", System.currentTimeMillis()
        );
        data.forEach((k, v) -> ReflectionUtils.setFieldValue(u, k, v));
        
        // 遍歷輸出
        for (FieldInfo fi : ReflectionUtils.getFieldInfos(u)) {
            Object val = ReflectionUtils.getFieldValue(u, fi.name);
            System.out.printf("%s (%s) = %s%n", fi.name, fi.type.getSimpleName(), val);
        }
    }
}

效能與安全注意事項

  • ⚡ 效能:反射比直接存取慢 10-100 倍。熱路徑建議緩存 `Field`/`Method` 物件,或使用 MethodHandle / VarHandle (Java 9+)
  • 🔒 安全:`setAccessible(true)` 破壞封裝,模組化系統 (JPMS) 可能限制,需在 `module-info.java` 加 `opens` 指令
  • 🧪 測試:單元測試、序列化框架、ORM 映射是反射主要合理用途;業務邏輯盡量避免

現代替代方案

  • Lombok @Data:編譯期生成 Getter/Setter,零反射開銷
  • MapStruct:編譯期生成映射程式碼,型別安全、效能極佳
  • Jackson / Gson:JSON 序列化內部已優化反射存取路徑

反射是雙面刃:框架開發的利器,業務程式碼的隱患。理解其原理與代價,在正確場景下謹慎使用。

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