您好,登錄后才能下訂單哦!
這篇文章主要講解了“Beanutils.copyProperties()的用法及重寫提高效率”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Beanutils.copyProperties()的用法及重寫提高效率”吧!
Beanutils.copyProperties()用法及重寫提高效率
一、簡介
二、用法
三、重寫
原理
BeanUtils.copyProperties 使用注意
示例演示
開始進行示例
最后強調
特別說明本文介紹的是Spring(import org.springframework.beans.BeanUtils)中的BeanUtils.copyProperties(A,B)方法。是將A中的值賦給B。apache(org.apache.commons.beanutils.BeanUtils)中的BeanUtils.copyProperties(A,B)方法是將B中的值賦值給A。
BeanUtils提供對Java反射和自省API的包裝。其主要目的是利用反射機制對JavaBean的屬性進行處理。我們知道,一個JavaBean通常包含了大量的屬性,很多情況下,對JavaBean的處理導致大量get/set代碼堆積,增加了代碼長度和閱讀代碼的難度。
如果你有兩個具有很多相同屬性的JavaBean,一個很常見的情況就是Struts里的PO對象(持久對象)和對應的ActionForm。例如:一個用戶注冊頁面,有一個User實體類和一個UserActionForm,我們一般會在Action里從ActionForm構造一個PO對象,傳統的方式是使用類似下面的語句對屬性逐個賦值:
// 獲取 ActionForm 表單數據 UserActionForm uForm = (UserActionForm) form; // 構造一個User對象 User user = new User(); // 逐一賦值 user.setUsername(uForm.getUsername); user.setPassword(uForm.getPassword); user.setAge(uForm.getAge); ........... ........... // 然后調用JDBC、或操作Hibernate 持久化對象User到數據庫 HibernateDAO.save(user);
通過這樣的方法如果表單數據N多、100、1000(夸張點。哈哈)、、、、那我們不是要寫100、、、1000行set、get了。誰都
不愿意這樣做。
而我們使用 BeanUtils.copyProperties() 方法以后,代碼量大大的減少,而且整體程序看著也簡潔明朗,代碼如下:
// 獲取 ActionForm 表單數據 UserActionForm uForm = (UserActionForm) form; // 構造一個User對象 User user = new User(); BeanUtils.copyProperties(uForm,user); // 然后調用JDBC、或操作Hibernate 持久化對象User到數據庫 HibernateDAO.save(user);
注:如果User和UserActionForm 間存在名稱不相同的屬性,則BeanUtils不對這些屬性進行處理,需要手動處理。例如:
User類里面有個createDate 創建時間字段,而UserActionForm里面無此字段。BeanUtils.copyProperties()不會對此字段做任何處理。必須要自己手動處理。
user.setModifyDate(new Date());
ReflectASM,高性能的反射:
什么是ReflectASM ReflectASM是一個很小的java類庫,主要是通過asm生產類來實現java反射,執行速度非常快,看了網上很多和反射的對比,覺得ReflectASM比較神奇,很想知道其原理,下面介紹下如何使用及原理;
public static void main(String[] args) { User user = new User(); //使用reflectasm生產User訪問類 MethodAccess access = MethodAccess.get(User.class); //invoke setName方法name值 access.invoke(user, "setName", "張三"); //invoke getName方法 獲得值 String name = (String)access.invoke(user, "getName", null); System.out.println(name); }
上面代碼的確實現反射的功能,代碼主要的核心是 MethodAccess.get(User.class);
看了下源碼,這段代碼主要是通過asm生產一個User的處理類 UserMethodAccess(這個類主要是實現了invoke方法)的ByteCode,然后獲得該對象,通過上面的invoke操作user類。
private static Map<Class, MethodAccess> methodMap = new HashMap<Class, MethodAccess>(); private static Map<String, Integer> methodIndexMap = new HashMap<String, Integer>(); private static Map<Class, List<String>> fieldMap = new HashMap<Class, List<String>>(); public static void copyProperties(Object desc, Object orgi) { MethodAccess descMethodAccess = methodMap.get(desc.getClass()); if (descMethodAccess == null) { descMethodAccess = cache(desc); } MethodAccess orgiMethodAccess = methodMap.get(orgi.getClass()); if (orgiMethodAccess == null) { orgiMethodAccess = cache(orgi); } List<String> fieldList = fieldMap.get(orgi.getClass()); for (String field : fieldList) { String getKey = orgi.getClass().getName() + "." + "get" + field; String setkey = desc.getClass().getName() + "." + "set" + field; Integer setIndex = methodIndexMap.get(setkey); if (setIndex != null) { int getIndex = methodIndexMap.get(getKey); // 參數一需要反射的對象 // 參數二class.getDeclaredMethods 對應方法的index // 參數對三象集合 descMethodAccess.invoke(desc, setIndex.intValue(), orgiMethodAccess.invoke(orgi, getIndex)); } } } // 單例模式 private static MethodAccess cache(Object orgi) { synchronized (orgi.getClass()) { MethodAccess methodAccess = MethodAccess.get(orgi.getClass()); Field[] fields = orgi.getClass().getDeclaredFields(); List<String> fieldList = new ArrayList<String>(fields.length); for (Field field : fields) { if (Modifier.isPrivate(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) { // 是否是私有的,是否是靜態的 // 非公共私有變量 String fieldName = StringUtils.capitalize(field.getName()); // 獲取屬性名稱 int getIndex = methodAccess.getIndex("get" + fieldName); // 獲取get方法的下標 int setIndex = methodAccess.getIndex("set" + fieldName); // 獲取set方法的下標 methodIndexMap.put(orgi.getClass().getName() + "." + "get" + fieldName, getIndex); // 將類名get方法名,方法下標注冊到map中 methodIndexMap.put(orgi.getClass().getName() + "." + "set" + fieldName, setIndex); // 將類名set方法名,方法下標注冊到map中 fieldList.add(fieldName); // 將屬性名稱放入集合里 } } fieldMap.put(orgi.getClass(), fieldList); // 將類名,屬性名稱注冊到map中 methodMap.put(orgi.getClass(), methodAccess); return methodAccess; } }
執行1000000條效率80幾毫秒,效率已經沒問題了。
首先結論說在前頭, BeanUtils.copyProperties 是淺拷貝 。
為什么今天我還想把這個BeanUtils.copyProperties 的使用拿出來軍訓。
因為我意識到了大家(部分)對深拷淺拷還是不清晰,不知道具體的影響。
第一個類:
第二個類:
注意!! 第二個類里面有使用第一個類。
public static void main(String[] args) { /** * 模擬數據 A complexObject */ ComplexObject complexObjectA=new ComplexObject(); complexObjectA.setNickName("張一"); SimpleObject simpleObject=new SimpleObject(); simpleObject.setName("李四"); simpleObject.setAge(12); complexObjectA.setSimpleObject(simpleObject); /** * 使用BeanUtils.copyProperties 拷貝 模擬數據 A 生成模擬數據 B */ ComplexObject complexObjectB=new ComplexObject(); BeanUtils.copyProperties(complexObjectA,complexObjectB); System.out.println("拷貝后,查看模擬數據A 和 模擬數據B :"); System.out.println(complexObjectA.getSimpleObject().toString()); System.out.println(complexObjectB.getSimpleObject().toString()); System.out.println("比較模擬數據A 和 模擬數據B 里面的引用對象simple 是否引用地址一樣: "); System.out.println(complexObjectA.getSimpleObject()==complexObjectB.getSimpleObject()); System.out.println("修改拷貝出來的模擬數據B里面的引用對象simple的屬性 age 為 888888"); complexObjectB.getSimpleObject().setAge(888888); System.out.println("修改后,觀察原數據A 和拷貝出來的數據 B 里面引用的 對象 simple的屬性 age:"); System.out.println(complexObjectA.getSimpleObject().toString()); System.out.println(complexObjectB.getSimpleObject().toString()); }
如果你是使用BeanUtils.copyProperties 進行對象的拷貝復制, 一定要注意!
第一點 、你所拷貝的對象內包不包含 其他對象的引用。
第二點、如果包含,那么接下來的方法里無論是操作原對象還是操作拷貝出來的對象是否涉及到 對 對象內 的 那個其他對象的 值的修改 。
第三點、如果涉及到, 修改了,會不會影響到其他方法 對 修改值的使用情況。
就如文中例子, 如果傳入過來的一個復雜對象數據A 里面引用了一個 user對象年齡age是10;拷貝出一份數據B后, 操作 數據B的方法把 年齡age改成了88888;
那么后續其他方法用到數據A ,想用的是最初始的 age 為10 ,那么就用不到了,因為淺拷貝的原因受影響,age都變成88888 了。
感謝各位的閱讀,以上就是“Beanutils.copyProperties()的用法及重寫提高效率”的內容了,經過本文的學習后,相信大家對Beanutils.copyProperties()的用法及重寫提高效率這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。