天天看點

java深拷貝的三種方式

問題:spring boot/JPA項目中,修改某個對象以後需要生成一個VO對象給用戶端,資料庫對應的POJO對象裡有個Map類型的對象(名字叫para),這個對象的value又是個Map,我使用Map的putAll()方法拷貝了一份para,然後修改裡面的值,最後發現para的内容也被修改了。示例代碼如下:

this.para.putAll(po.getPara());
// fields是para下面的一個Map參數,此處本意是傳回給用戶端的fields元素中不包含aaa和bbb兩個字段
			List<Map<String, Object>> fields = (List<Map<String, Object>>)this.para.get("fields");
			fields.forEach(item -> {
				item.remove("aaa");
				item.remove("bbb");
			});
           

以上代碼出現的問題是,傳回給界面的VO中确實沒有了aaa和bbb兩個字段,但不幸的是,對應資料庫中的fields中也沒有了這兩個字段,這不是期望的。

原因:map的putAll實作的是淺拷貝。

解決方法:實作深拷貝,有三種方式:

  1. 手動指派,效率高,但代碼過于啰嗦。
  2. 序列化與反序列化,使用SerializationUtils的clone(Object obj)方法,要求拷貝的對象實作了Serializable,Map不行,使用HashMap即可。
  3. 用fastjson從Object轉成json,然後轉回object,本質上是反射:
    private Object deepCopyByJson(Object obj) {
         String json = JSON.toJSONString(obj);
         return JSON.parseObject(json, Object.class);
     }
               
    具體使用哪種方法視具體場景而定,我解決這個問題用的是SerializationUtils,性能要求不高的情況下代碼簡潔也很重要。
  4. 解決方式:
this.para = (Map<String, Object>) SerializationUtils.clone((HashMap<String, Object>)po.getPara());