Map的putAll方法踩坑实记(对象深拷贝浅拷贝)
文章目錄
- 問題描述
- 編寫測試代碼模擬問題場景
- 場景1:Map中不包含對象
- 場景2:Map中包含對象
- 什么是對象的淺拷貝深拷貝
- 如何實現深拷貝
問題描述
在一個產品管理系統中,產品信息需要封裝一份同步業務訂單系統,封裝同步信息的時候需要對產品信息做一些修改,同步完信息再將產品信息進行入庫等操作。開發中就是使用的Map對象封裝信息,但是總是發現入庫信息和創建信息不一致的情況。
操作步驟偽代碼如下:
//創建產品信息 createProdInfo(); //執行訂單同步信息封裝 packageProdInfo(); //執行訂單同步服務操作 synProdInfo(); //上面操作都成功了,執行入庫操作 insertProdInfo();編寫測試代碼模擬問題場景
場景1:Map中不包含對象
使用Map封裝產品信息,產品中value都是字符串類型,并沒有其他Object對象的情況下
@Testpublic void putAllTest1() throws InterruptedException {String crtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//產品創建時間Map<String, Object> prodInfo = new HashMap<>();//產品prodInfo.put("prodId", "1");//產品IDprodInfo.put("prodName", "AI產品");//產品名稱prodInfo.put("prodDesc", "這是個AI產品,智能連接未來");//產品描述prodInfo.put("isMain", "1");//是否是主產品prodInfo.put("crtTime", crtTime);//創建時間System.out.println("原產品信息:" + JSON.toJSONString(prodInfo));Map<String, Object> synProdInfo = new HashMap<>();//同步產品信息TimeUnit.SECONDS.sleep(3);//模擬同步產品信息耗時3秒String synCrtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());synProdInfo.putAll(prodInfo);synProdInfo.put("systemId", "order");//同步系統IDsynProdInfo.put("systemName", "訂單系統");//同步系統名稱synProdInfo.put("crtTime", synCrtTime);//同步訂單同步時間System.out.println("同步信息內容:" + JSON.toJSONString(synProdInfo));System.out.println("產品入庫信息:" + JSON.toJSONString(prodInfo));}測試結果:
原產品信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:45:59","prodId":"1","prodDesc":"這是個AI產品,智能連接未來"} 同步信息內容:{"systemId":"order","systemName":"訂單系統","isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:46:02","prodId":"1","prodDesc":"這是個AI產品,智能連接未來"} 產品入庫信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:45:59","prodId":"1","prodDesc":"這是個AI產品,智能連接未來"}
上面這種情況是符合要求的情況,同步信息crtTime的修改并沒有影響產品入庫時間。但是出問題的場景是比這種更為復雜的情況,就是產品下面帶有子產品信息的情況。
場景2:Map中包含對象
使用Map封裝產品信息,產品中包含Map對象的的情況下,測試代碼如下:
@Testpublic void putAllTest2() throws InterruptedException {String crtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//產品創建時間Map<String, Object> prodInfo = new HashMap<>();//產品prodInfo.put("prodId", "1");//產品IDprodInfo.put("prodName", "AI產品");//產品名稱prodInfo.put("prodDesc", "這是個AI產品,智能連接未來");//產品描述prodInfo.put("isMain", "1");//是否是主產品,1是0不是prodInfo.put("crtTime", crtTime);//創建時間Map<String, Object> childProdInfo = new HashMap<>();childProdInfo.put("prodId", "2");//產品IDchildProdInfo.put("prodName", "5G產品");//產品名稱childProdInfo.put("prodDesc", "這是個5G產品");//產品描述childProdInfo.put("isMain", "0");//是否是主產品,1是0不是childProdInfo.put("crtTime", crtTime);//創建時間prodInfo.put("childProdInfo", childProdInfo);//子產品信息System.out.println("原產品信息:" + JSON.toJSONString(prodInfo));Map<String, Object> synProdInfo = new HashMap<>();//同步產品信息TimeUnit.SECONDS.sleep(3);//模擬同步產品信息耗時3秒String synCrtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());synProdInfo.putAll(prodInfo);synProdInfo.put("systemId", "order");//同步系統IDsynProdInfo.put("systemName", "訂單系統");//同步系統名稱synProdInfo.put("crtTime", synCrtTime);//同步訂單同步時間Map<String,Object> synChildProdInfo = (Map<String, Object>) synProdInfo.get("childProdInfo");//獲取子產品信息synChildProdInfo.put("systemId", "order");//同步系統IDsynChildProdInfo.put("systemName", "訂單系統");//同步系統名稱synChildProdInfo.put("crtTime", synCrtTime);//同步訂單同步時間System.out.println("原同步信息內容:" + JSON.toJSONString(synProdInfo));System.out.println("產品入庫信息:" + JSON.toJSONString(prodInfo));}日志輸出如下:
原產品信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:57:07","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 21:57:07","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"} 原同步信息內容:{"systemId":"order","systemName":"訂單系統","isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:57:10","prodId":"1","childProdInfo":{"systemId":"order","systemName":"訂單系統","isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 21:57:10","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"} 產品入庫信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 21:57:07","prodId":"1","childProdInfo":{"systemId":"order","systemName":"訂單系統","isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 21:57:10","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"}這里發現主產品的創建時間和入庫的時候一致但是子產品的創建時間和其入庫時間不一致了,但是和同步創建時間一致了。
這說明,同步信息封裝的時候修改了子產品的信息,這并不是我們想要的結果。這里其實就涉及到對象的淺拷貝和深拷貝的問題。
什么是對象的淺拷貝深拷貝
簡單來說就是:
淺拷貝:對基本數據類型進行值傳遞,對引用數據類型進行引用傳遞般的拷貝,此為淺拷貝。
深拷貝:對基本數據類型進行值傳遞,對引用數據類型,創建一個新的對象,并復制其內容,此為深拷貝。
如何實現深拷貝
序列化的方式可以實現對象的深拷貝,但是對象必須是實現了Serializable接口才可以,Map本身沒有實現 Serializable 這個接口,不能實現深拷貝,但是HashMap實現了Serializable,可以進行深拷貝。
首先,附上深拷貝的方法
其次,對我們的代碼稍作修改
@Testpublic void putAllTest3() throws InterruptedException {String crtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//產品創建時間HashMap<String, Object> prodInfo = new HashMap<>();//產品,此處修改為HashMapprodInfo.put("prodId", "1");//產品IDprodInfo.put("prodName", "AI產品");//產品名稱prodInfo.put("prodDesc", "這是個AI產品,智能連接未來");//產品描述prodInfo.put("isMain", "1");//是否是主產品,1是0不是prodInfo.put("crtTime", crtTime);//創建時間Map<String, Object> childProdInfo = new HashMap<>();childProdInfo.put("prodId", "2");//產品IDchildProdInfo.put("prodName", "5G產品");//產品名稱childProdInfo.put("prodDesc", "這是個5G產品");//產品描述childProdInfo.put("isMain", "0");//是否是主產品,1是0不是childProdInfo.put("crtTime", crtTime);//創建時間prodInfo.put("childProdInfo", childProdInfo);//子產品信息System.out.println("原產品信息:" + JSON.toJSONString(prodInfo));Map<String, Object> synProdInfo = new HashMap<>();//同步產品信息TimeUnit.SECONDS.sleep(3);//模擬同步產品信息耗時3秒String synCrtTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());synProdInfo = clone(prodInfo);//此處使用深拷貝賦值synProdInfo.put("systemId", "order");//同步系統IDsynProdInfo.put("systemName", "訂單系統");//同步系統名稱synProdInfo.put("crtTime", synCrtTime);//同步訂單同步時間Map<String, Object> synChildProdInfo = (Map<String, Object>) synProdInfo.get("childProdInfo");//獲取子產品信息synChildProdInfo.put("systemId", "order");//同步系統IDsynChildProdInfo.put("systemName", "訂單系統");//同步系統名稱synChildProdInfo.put("crtTime", synCrtTime);//同步訂單同步時間System.out.println("原同步信息內容:" + JSON.toJSONString(synProdInfo));System.out.println("產品入庫信息:" + JSON.toJSONString(prodInfo));}測試結果如下:
原產品信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 22:53:26","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 22:53:26","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"} 原同步信息內容:{"systemId":"order","systemName":"訂單系統","isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 22:53:29","prodId":"1","childProdInfo":{"systemId":"order","systemName":"訂單系統","isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 22:53:29","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"} 產品入庫信息:{"isMain":"1","prodName":"AI產品","crtTime":"2020-04-18 22:53:26","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G產品","crtTime":"2020-04-18 22:53:26","prodId":"2","prodDesc":"這是個5G產品"},"prodDesc":"這是個AI產品,智能連接未來"}這里的產品創建時間、子產品創建時間都和入庫時間一致了
至此,解決了由于putAll引起的問題,這個在使用的時候需要注意。
總結
以上是生活随笔為你收集整理的Map的putAll方法踩坑实记(对象深拷贝浅拷贝)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql常见的sql语法示例
- 下一篇: java程序中date类型比较大小总结