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

JavaBean 屬性拷貝實戰:從 Apache BeanUtils 到反射機制自建工具類

     編輯:Java 相關知識

痛點:重複的 Getter/Setter 代碼

Struts 開發中,ActionForm 與資料庫實體 Bean 頻繁交換數據。傳統寫法需逐屬性調用 get/set,代碼冗長、易錯、維護成本高,嚴重消磨編程樂趣。

方案一:站在巨人肩膀上——Apache Commons BeanUtils

Apache Commons BeanUtils 提供 BeanUtils.copyProperties(dest, src) 靜態方法,一行代碼完成屬性拷貝,自動匹配同名屬性,支援類型轉換,生產環境首選。

方案二:深入原理——基於 Java 反射機制自建拷貝工具

理解反射機制不僅能造輪子,更能在框架無法滿足特殊需求時靈活擴展。

核心邏輯

  1. 獲取源對象所有 getXxx() 方法
  2. 獲取目標對象所有 setXxx() 方法
  3. 按屬性名(去除 get/set 前綴)匹配
  4. 調用源對象 getter 獲取值,調用目標對象 setter 設定值

完整實現代碼

import java.lang.reflect.Method;

public class BeanUtil2 {

    /**
     * 將 obj1 的屬性值拷貝到 obj2
     * @param obj1 源對象(需有 public getter)
     * @param obj2 目標對象(需有 public setter)
     * @return 目標對象
     */
    public static Object copyBeanToBean(Object obj1, Object obj2) throws Exception {
        Method[] methods1 = obj1.getClass().getMethods();
        Method[] methods2 = obj2.getClass().getMethods();

        for (Method m1 : methods1) {
            String name1 = m1.getName();
            if (!name1.startsWith("get")) continue;
            String propName = name1.substring(3); // 去除 "get"

            for (Method m2 : methods2) {
                String name2 = m2.getName();
                if (!name2.startsWith("set")) continue;
                if (propName.equals(name2.substring(3))) { // 匹配屬性名
                    Object value = m1.invoke(obj1, new Object[0]);
                    m2.invoke(obj2, new Object[]{value});
                    break; // 找到對應 setter 即跳出內層循環
                }
            }
        }
        return obj2;
    }
}

測試驗證

public class User {
    private String name;
    private String 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();
        u2 = (User) BeanUtil2.copyBeanToBean(u1, u2);
        
        System.out.println(u2.getName()); // 輸出: zxb
        System.out.println(u2.getId());   // 輸出: 3286
    }
}

進階考量與最佳實踐

  • 類型兼容性:生產級工具需處理類型轉換(如 String ↔ Integer)
  • 只讀/寫只屬性:需檢查 setter/getter 是否存在
  • 性能優化:緩存 Method 對象、使用 MethodHandle(Java 7+)
  • 現有成熟庫:Spring BeanUtils、Dozer、MapStruct(編譯期生成代碼、性能最優)

總結

屬性拷貝是企業級開發高頻需求。優先使用成熟開源庫;理解反射原理可應對特殊場景、排查框架問題;追求極致性能可採用 MapStruct 等編譯期代碼生成方案。工具服務於業務,切勿為造輪子而造輪子。

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