文章目录

  • 问题描述
  • 编写测试代码模拟问题场景
    • 场景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,可以进行深拷贝。
首先,附上深拷贝的方法

    /*** 使用对象的序列化进而实现深拷贝* @param obj* @param <T>* @return*/private <T extends Serializable> T clone(T obj) {T cloneObj = null;try {ByteOutputStream bos = new ByteOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(obj);oos.close();ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);cloneObj = (T) ois.readObject();ois.close();} catch (Exception e) {e.printStackTrace();}return cloneObj;}

其次,对我们的代码稍作修改

    @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方法踩坑实记(对象深拷贝浅拷贝)相关推荐

  1. 【浙政钉】微信-专有钉钉小程序-开发踩坑实记

    文章目录 ⭐[浙政钉]微信-专有钉钉小程序-开发踩坑实记 ⭐ 创建项目 ⭐ 转化方案 ⭐ 政务钉钉调试 ⭐ 上传发布 ⭐[浙政钉]微信-专有钉钉小程序-开发踩坑实记 最近有个需求,要将微信小程序转为浙 ...

  2. Mint-UI框架router-link返回上一页的方法 - 踩坑篇

    使用mint-ui框架的header导航组件,<router-link to="">如何实现点击返回上一页? 代码如下: <template><!-- ...

  3. Android里面的settext作用,Android EditText setText方法踩坑实录

    1.平平常常中就这样开始 某一天,我准备做一个搜索功能,这个搜索功能呢大概是在主活动A中,用EditText接收输入,当EditText监听到输入框中内容有变化,跳转到活动B中,活动B中准备有搜索历史 ...

  4. ubuntu18.04下载python3.70的方法--踩坑日记

    主要参考博客 python官网下载这个就行 1. 首先,我查看了自己的python版本为2.7,所以我下载了python官网的3.70的tgz包,然后按照这篇博客去安装 在第九步install的时候报 ...

  5. laravel map方法踩坑记录

    用map方法编辑集合的时候,集合中存在关联查询结果是相同的时候,进行修改回出现修改A会影响B的情况 例如 代码逻辑 //以下数据遍历第一次的时候,修改$item新增属性node_type,会影响第二次 ...

  6. 微信小程序录制视频方法踩坑总结

    ** 工作中需要微信小程序实现录制15s视频上传,部分用户反馈无法录制视频的问题,所以在此总结一下经验 ** 下面这张图片这是问题的表现,部分机型用户松开拍摄时提示未完成拍摄,导致无法上传视频. 上面 ...

  7. 将知网下载的CAJ文件转为PDF 踩坑详记

    最近在做文献综述,硕博论文下载下来都是caj然后阅读体验无力吐槽哈哈哈然后翻译,经过朋友的xhs帖子发现新大陆然后牛刀小试一下哈哈哈哈然后记录一哈其中曲折的路程,提供几种方法~ 方法一:利用micro ...

  8. Python 酷q,踩坑粗记,用慕晓飞大神的sdk

    一.安装,此处坑在文档中都有,需要注意的是vs_redit用x86的,文档上的地址我没有试,直接用2008-2019的64位就没成功,安上32位的2017就可以加载dll和json这些文件了 二.当时 ...

  9. JavaScript replaceAll() 方法踩坑

    IE 浏览器中不支持 replaceAll() 方法,所以会导致某些功能在 IE.搜狗等浏览器中无效. 具体功能看个人在哪里用了这个方法,例如我是在页面跳转之前的函数里用了这个方法,所以导致在 IE. ...

最新文章

  1. SAP项目里的关键用户,兼职还是专职?
  2. Nacos源码Notifier异步更新
  3. [Objective-C]编程艺术 笔记整理
  4. 统计学基础学习笔记:正态分布
  5. R语言编程基础(1)
  6. js 字符串去空格方法
  7. ipad上linux终端,如何使用iSH在iPad或iPhone上获取Linux Shell
  8. 最新搜索引擎网站提交登录入口和收录入口大全
  9. windows10 关闭欢迎界面
  10. pr视频两边模糊_pr教程:如何制作视频画面局部模糊效果?-吾尊时尚
  11. sap系统webservice接口开发
  12. 如何下载高程地图并处理
  13. php 图片上加文字,PHP语言之给图片添加文字(支持中文)//PHP函数
  14. AI之路最近的一些思考
  15. 双击ie浏览器没反应打不开的解决方法
  16. 【对象存储】关于阿里云OSS踩坑记录
  17. [Unity] 自定义日志系统 解决Unity Log的痛点
  18. 创意名片大全:一组精美的折叠效果名片设计
  19. 颜色大全:颜色名称和颜色值。色板、色板对照表1
  20. 与其让黑客有机可乘,不如用MCK保驾护航

热门文章

  1. 实施hybris必须懂java吗
  2. SAP 关于ABAP TABLE BUFFER的解释
  3. SAP FICO年结
  4. 盒马加速布局,生鲜新零售如何“中场进阶”?
  5. 罗永浩直播带货花落谁家?不止是价高者得之
  6. python连接mongodb进行查询_Python中的MongoDB基本操作:连接、查询实例
  7. smarty能创建 php页面,php+smarty生成静态页面详解
  8. php超链接如何隐藏参数,php如何去除超链接
  9. python的烦恼_还在为每天忘记签到而烦恼吗?python来帮你搞定!
  10. 一篇文章学会Python函数重写,每天进步一个知识点