Struts 開發中,ActionForm 與資料庫實體 Bean 頻繁交換數據。傳統寫法需逐屬性調用 get/set,代碼冗長、易錯、維護成本高,嚴重消磨編程樂趣。
Apache Commons BeanUtils 提供 BeanUtils.copyProperties(dest, src) 靜態方法,一行代碼完成屬性拷貝,自動匹配同名屬性,支援類型轉換,生產環境首選。
理解反射機制不僅能造輪子,更能在框架無法滿足特殊需求時靈活擴展。
getXxx() 方法setXxx() 方法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
}
}
BeanUtils、Dozer、MapStruct(編譯期生成代碼、性能最優)屬性拷貝是企業級開發高頻需求。優先使用成熟開源庫;理解反射原理可應對特殊場景、排查框架問題;追求極致性能可採用 MapStruct 等編譯期代碼生成方案。工具服務於業務,切勿為造輪子而造輪子。