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

Commons Collections 學習筆記(四):BeanMap - JavaBean 與 Map 雙向轉換利器

     編輯:Java 相關知識

BeanMap 是 Commons Collections 提供的特殊 Map 實作,能將任意 JavaBean 自動轉換為 Map,鍵為屬性名,值為屬性值,支援雙向讀寫、型別轉換、複製與事件通知,極適合表單綁定、配置映射、泛型資料存取等場景。

核心架構與欄位

public class BeanMap extends AbstractMap implements Cloneable {
    private transient Object bean;                    // 底層 JavaBean 實例
    private transient HashMap readMethods = new HashMap();  // 屬性名 → getter Method
    private transient HashMap writeMethods = new HashMap(); // 屬性名 → setter Method
    private transient HashMap types = new HashMap();        // 屬性名 → 屬性 Class
    // 預設型別轉換器:字串 → 基本型別包裝類
    public static HashMap defaultTransformers = new HashMap();
}

關鍵功能解析

1. 自動內省初始化

private void initialise() {
    BeanInfo info = Introspector.getBeanInfo(bean.getClass());
    for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
        String name = pd.getName();
        if (pd.getReadMethod() != null) readMethods.put(name, pd.getReadMethod());
        if (pd.getWriteMethod() != null) writeMethods.put(name, pd.getWriteMethod());
        types.put(name, pd.getPropertyType());
    }
}
  • 建構子 BeanMap(Object bean) 呼叫 initialise() 掃描所有可讀寫屬性。
  • 利用 Introspector 標準 JavaBeans 內省機制,零配置自動發現。

2. Map 介面核心實作

public Object get(Object name) {
    Method getter = getReadMethod(name);
    return (getter != null) ? getter.invoke(bean, NULL_ARGUMENTS) : null;
}

public Object put(Object name, Object value) {
    Method setter = getWriteMethod(name);
    if (setter == null) throw new IllegalArgumentException("No property: " + name);
    Object old = get(name);
    Object[] args = createWriteMethodArguments(setter, value); // 型別轉換
    setter.invoke(bean, args);
    firePropertyChange(name, old, get(name)); // 觸發屬性變更事件
    return old;
}
  • get/put 透過反射動態調用 getter/setter。
  • createWriteMethodArguments 自動處理型別轉換(見下)。
  • 整合 PropertyChangeListener 機制,支援綁定框架。

3. 智慧型別轉換機制

protected Object convertType(Class targetType, Object value) {
    // 1. 嘗試單參數建構子:new TargetType(value)
    // 2. 失敗則查找 defaultTransformers(字串 → 基本型別包裝類)
    // 3. 仍失敗則回傳原值
}
  • 預設支援所有基本型別 + String 互轉。
  • 可自訂 Transformer 擴充轉換邏輯(如日期解析)。

4. 深度複製支援

public Object clone() {
    BeanMap copy = (BeanMap) super.clone();
    Object newBean = bean.getClass().newInstance(); // 新實例
    copy.setBean(newBean);
    // 複製所有可讀寫屬性值
    for (Object key : readMethods.keySet()) {
        if (getWriteMethod(key) != null) copy.put(key, get(key));
    }
    return copy;
}
  • 建立新 Bean 實例並複製所有屬性值,而非共享同一 Bean。
  • clear() 則重新實例化底層 Bean 回初始狀態。

5. 自訂 Map.Entry 實作

protected static class MyMapEntry extends AbstractMapEntry {
    private BeanMap owner;
    public Object setValue(Object value) {
        Object old = owner.get(getKey());
        owner.put(getKey(), value);
        super.setValue(owner.get(getKey()));
        return old;
    }
}
  • entry.setValue() 直接委派 BeanMap.put(),保持同步。

實際應用場景

場景用法
表單資料綁定HTTP 參數 Map → BeanMap → 自動填充 JavaBean
配置物件化Properties → BeanMap → 強型別配置 Bean
泛型資料存取層以 Map 介面統一存取不同 Bean,支援序列化/複製
測試資料構建快速建立 Bean 並透過 Map 介面批量設值

使用範例

public class User {
    private String name; private int age;
    // getter/setter...
}

User user = new User();
BeanMap map = new BeanMap(user);
map.put("name", "Alice");
map.put("age", "25"); // 字串自動轉 int
System.out.println(user.getName()); // Alice
System.out.println(user.getAge());  // 25

// 複製
BeanMap copy = (BeanMap) map.clone();
copy.put("age", 26);
System.out.println(user.getAge());  // 25 (原物件未變)
System.out.println(((User)copy.getBean()).getAge()); // 26

結語

BeanMap 以標準內省機制橋接 JavaBean 與 Map 世界,提供型別安全、事件驅動、可複製的雙向存取層。掌握其轉換機制與複製語義,能大幅簡化表單處理、配置管理與測試資料構建等常見任務。

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