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

Java 反射實現對象屬性自動拷貝:支持巢狀對象的通用工具類

     編輯:Java 綜合教學

Java 反射實現對象屬性自動拷貝:支持巢狀對象的通用工具類

在系統對接中,常需將前置系統的對象轉換為內部領域對象,再經處理後轉回。手寫 set/get 代碼冗長且難維護,本文提供基於反射的通用拷貝工具,支持基本類型、包裝類、String、Date 及巢狀對象遞歸拷貝。

核心思路

  1. 獲取源對象所有聲明字段 getDeclaredFields()。
  2. 遍歷字段,設置可訪問 setAccessible(true)。
  3. 根據字段類型構造 Getter 方法名(boolean 型為 isXxx,其餘 getXxx)。
  4. 調用 Getter 獲取值,在目標對象中查找同名字段,調用 Setter 賦值。
  5. 若字段為非基本類型(即自定義對象),遞歸調用拷貝方法處理巢狀對象。

完整工具類代碼

public class BeanCopier {
    public static void copy(Object src, Object dest) throws Exception {
        doField(src, dest);
    }

    private static void doField(Object src, Object dest) throws Exception {
        Field[] srcFields = src.getClass().getDeclaredFields();
        Field[] destFields = dest.getClass().getDeclaredFields();

        for (Field sf : srcFields) {
            boolean accessible = sf.isAccessible();
            sf.setAccessible(true);
            String name = sf.getName();
            String getter = (sf.getType() == boolean.class || sf.getType() == Boolean.class) ? "is" + capitalize(name) : "get" + capitalize(name);
            Method getMethod = src.getClass().getDeclaredMethod(getter);
            Object value = getMethod.invoke(src);

            for (Field df : destFields) {
                if (df.getName().equals(name)) {
                    df.setAccessible(true);
                    if (isPrimitiveOrWrapper(df.getType())) {
                        // 基本類型、包裝類、String、Date 直接賦值
                        if (df.getType() == boolean.class || df.getType() == Boolean.class) {
                            df.set(dest, "1".equals(value) ? true : false); // 兼容字符串 "1"/"0"
                        } else {
                            df.set(dest, value);
                        }
                    } else {
                        // 巢狀對象:創建實例並遞歸拷貝
                        Object nestedDest = df.getType().getDeclaredConstructor().newInstance();
                        doField(value, nestedDest);
                        df.set(dest, nestedDest);
                    }
                    System.out.println(df.getName() + ":" + df.get(dest));
                    break;
                }
            }
            sf.setAccessible(accessible);
        }
    }

    private static boolean isPrimitiveOrWrapper(Class<?> clazz) {
        return clazz.isPrimitive() || clazz == String.class || clazz == Date.class ||
               clazz == Byte.class || clazz == Short.class || clazz == Integer.class ||
               clazz == Long.class || clazz == Float.class || clazz == Double.class ||
               clazz == Character.class || clazz == Boolean.class;
    }

    private static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}

使用示例

MtUserInfoRule src = new MtUserInfoRule();
// 設置 src 各字段及巢狀對象 Person -> Student
UserInfoRule dest = new UserInfoRule();
BeanCopier.copy(src, dest); // 一行代碼完成深拷貝

局限性與改進方向

  • 數組/集合類型(如 String[]、List<T>)未完全支持,需增加集合實例化與元素遞歸邏輯。
  • 字段名不一致時無法匹配,可引入註解 @Mapping("targetField") 指定映射。
  • 性能敏感場景可考慮字節碼生成(如 CGLIB BeanCopier)替代反射。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved