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

JavaBean 屬性拷貝實戰:反射實現通用 Copy 工具與 Apache BeanUtils 對比

     編輯:Java 程式設計入門

痛點:手寫 Getter/Setter 的重複勞動

// 典型場景:ActionForm → Domain Object
user.setName(form.getName());
user.setId(form.getId());
user.setEmail(form.getEmail());
// ... 幾十行重複代碼

方案一:Apache Commons BeanUtils(生產首選)

// 一行搞定
BeanUtils.copyProperties(dest, src);
  • 支援基本類型轉換、集合、Map、索引屬性
  • 可配置 ConvertUtils 自訂類型轉換器
  • 內部快取 PropertyDescriptor,效能優於手寫反射
  • 異常處理:InvocationTargetException、IllegalAccessException

方案二:手寫反射工具(教學/輕量/無依賴)

public class BeanCopier {
    public static void copy(Object src, Object dest) throws Exception {
        Method[] srcMethods = src.getClass().getMethods();
        Method[] destMethods = dest.getClass().getMethods();
        Map destSetters = new HashMap<>();
        for (Method m : destMethods) {
            if (m.getName().startsWith("set") && m.getParameterCount() == 1) {
                String prop = m.getName().substring(3);
                destSetters.put(prop, m);
            }
        }
        for (Method m : srcMethods) {
            if (m.getName().startsWith("get") && m.getParameterCount() == 0) {
                String prop = m.getName().substring(3);
                Method setter = destSetters.get(prop);
                if (setter != null) {
                    Object value = m.invoke(src);
                    setter.invoke(dest, value);
                }
            }
        }
    }
}

關鍵細節與坑點

問題說明對策
Boolean 存取器可能是 isXxx() 而非 getXxx()同時檢查 get/is 前綴
不可讀/寫屬性只有 getter 或只有 setter雙向存在時才拷貝
類型不匹配src.getXxx() 返回類型與 dest.setXxx() 參數不兼容加入類型轉換邏輯或拋出明確異常
私有/繼承方法getMethods() 含繼承公開方法;getDeclaredMethods() 含私有通常用 getMethods() 符合 JavaBean 規範
效能反射慢於直接調用快取 Method 物件、或用 MethodHandle/字節碼生成

進階:MapStruct 編譯期生成(高效能、類型安全)

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    UserDto toDto(UserEntity entity);
    // 編譯期生成實現:直接調用 getter/setter,零反射
}
  • 編譯期生成代碼,運行零開銷
  • 類型不匹配編譯報錯,而非運行時拋異常
  • 支援自定義映射邏輯、條件映射、集合映射

測試驗證

public class User {
    private String name, id;
    // getter/setter 省略
    public static void main(String[] args) throws Exception {
        User u1 = new User(); u1.setName("zxb"); u1.setId("3286");
        User u2 = new User();
        BeanCopier.copy(u1, u2);
        System.out.println(u2.getName()); // zxb
        System.out.println(u2.getId());   // 3286
    }
}

選型建議

  1. 一般專案:Apache BeanUtils / Spring BeanUtils(BeanUtils.copyProperties)
  2. 高效能/核心路徑:MapStruct(編譯期生成)
  3. 無第三方依賴限制:手寫反射工具(加上快取優化)
  4. 複雜映射:MapStruct 或 Dozer(運行時映射引擎)

總結

JavaBean 屬性拷貝是企業級開發高頻需求。理解反射機制、PropertyDescriptor、類型轉換體系,能讓你在選型、排查、優化時遊刃有餘。現代專案首推 MapStruct:編譯期安全、運行極致效能、IDE 友好重構支援。

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