700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Map的putAll方法踩坑实记(对象深拷贝浅拷贝)

Map的putAll方法踩坑实记(对象深拷贝浅拷贝)

时间:2020-01-03 10:19:11

相关推荐

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":"-04-18 21:45:59","prodId":"1","prodDesc":"这是个AI产品,智能连接未来"}同步信息内容:{"systemId":"order","systemName":"订单系统","isMain":"1","prodName":"AI产品","crtTime":"-04-18 21:46:02","prodId":"1","prodDesc":"这是个AI产品,智能连接未来"}产品入库信息:{"isMain":"1","prodName":"AI产品","crtTime":"-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":"-04-18 21:57:07","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G产品","crtTime":"-04-18 21:57:07","prodId":"2","prodDesc":"这是个5G产品"},"prodDesc":"这是个AI产品,智能连接未来"}原同步信息内容:{"systemId":"order","systemName":"订单系统","isMain":"1","prodName":"AI产品","crtTime":"-04-18 21:57:10","prodId":"1","childProdInfo":{"systemId":"order","systemName":"订单系统","isMain":"0","prodName":"5G产品","crtTime":"-04-18 21:57:10","prodId":"2","prodDesc":"这是个5G产品"},"prodDesc":"这是个AI产品,智能连接未来"}产品入库信息:{"isMain":"1","prodName":"AI产品","crtTime":"-04-18 21:57:07","prodId":"1","childProdInfo":{"systemId":"order","systemName":"订单系统","isMain":"0","prodName":"5G产品","crtTime":"-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":"-04-18 22:53:26","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G产品","crtTime":"-04-18 22:53:26","prodId":"2","prodDesc":"这是个5G产品"},"prodDesc":"这是个AI产品,智能连接未来"}原同步信息内容:{"systemId":"order","systemName":"订单系统","isMain":"1","prodName":"AI产品","crtTime":"-04-18 22:53:29","prodId":"1","childProdInfo":{"systemId":"order","systemName":"订单系统","isMain":"0","prodName":"5G产品","crtTime":"-04-18 22:53:29","prodId":"2","prodDesc":"这是个5G产品"},"prodDesc":"这是个AI产品,智能连接未来"}产品入库信息:{"isMain":"1","prodName":"AI产品","crtTime":"-04-18 22:53:26","prodId":"1","childProdInfo":{"isMain":"0","prodName":"5G产品","crtTime":"-04-18 22:53:26","prodId":"2","prodDesc":"这是个5G产品"},"prodDesc":"这是个AI产品,智能连接未来"}

这里的产品创建时间、子产品创建时间都和入库时间一致了

至此,解决了由于putAll引起的问题,这个在使用的时候需要注意。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。