当前位置: 首页 > news >正文

新昌网站开发网络游戏开服表

新昌网站开发,网络游戏开服表,传奇霸主页游,环球资源网的定位今天想写一篇文章,主要关于深拷贝和浅拷贝相关的,主要是最近写代码的时候遇到一个BUG,刚好涉及到浅拷贝导致的问题。 问题背景 现在有一个需要是需要修改门店信息,门店也区分父门店和子门店,父门店被编辑更新是需要通过…

今天想写一篇文章,主要关于深拷贝和浅拷贝相关的,主要是最近写代码的时候遇到一个BUG,刚好涉及到浅拷贝导致的问题。

问题背景

现在有一个需要是需要修改门店信息,门店也区分父门店和子门店,父门店被编辑更新是需要通过到第三方的,然后之前是没有父子门店的概念的,后面新增的需求,然后editShop这个方法的入参就是关于门店的信息么,这里我简化它的参数,但是保留了一个data属于引用型参数。

下面的模拟当时出现BUG的代码

public class RequestDto {Map<String, Object> data = new HashMap<>();private Integer status ;private Long id;public Map<String, Object> getData() {return data;}
}public class ShopService {public void editShop(RequestDto requestDto) {System.out.println("入参:" + requestDto.toString());// 操作// 父门店获取子门店,假设有两个List<Long> childShops = getChildShop(requestDto.getId());childShops.stream().forEach(childShop -> {RequestDto requestDto1 = new RequestDto();BeanUtils.copyProperties(requestDto, requestDto1);requestDto1.setId(childShop);requestDto1.getData().put("isSync", Boolean.FALSE);editShop(requestDto1);sync(childShop);});System.out.println("返回前:" + requestDto.toString());if (Boolean.FALSE.equals(requestDto.getData().get("isSync"))) {return;}sync(requestDto.getId());}private List<Long> getChildShop(Long parentId) {if (parentId.equals(1L)) {// 父门店List<Long> childShopIds = new ArrayList<>();childShopIds.add(123L);childShopIds.add(234L);return childShopIds;} else {return new ArrayList<>();}}private void sync(Long shopId) {System.out.println("同步门店第三方:" + shopId);}
}
public class Main {public static void main(String[] args) {ShopService shopService = new ShopService();RequestDto requestDto = new RequestDto();requestDto.setId(1L);requestDto.setStatus(0);shopService.editShop(requestDto);}}

模拟了当时操作父门店时,需要触发子门店的配置信息同步,通过递归来实现似乎是不错的选择,但是将isSync作为递归结束的标志来,然后就可以完成配置的复制和更新,看起来是没有什么问题的,但是当这个代码真的到达线上的时候,发现编辑父门店,子门店触发通过不了,但是父门店就触发不了同步了,在判断的if里面就退出了,导致线上发现父门店配置没有同步的BUG。然后经过一顿头发输出,看了好几遍日志之后,也没有发现问题的所在,后面本地起了一个调试才发现,这个问题是出自于BeanUtils.copyProperties的问题,排查出来了。

BeanUtils.copyProperties的时候,已经将requestDto1中data的引用指向了requestDto的引用,然后对它添加isSync的时候是会导致父门店的dto也同时被修改了。

在这里插入图片描述

BeanUtils.copyProperties的源码分析

private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,@Nullable String... ignoreProperties) throws BeansException {Assert.notNull(source, "Source must not be null");Assert.notNull(target, "Target must not be null");Class<?> actualEditable = target.getClass();if (editable != null) {if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() +"] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}// 获取所有的属性PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);// 遍历for (PropertyDescriptor targetPd : targetPds) {// 写入的set方法Method writeMethod = targetPd.getWriteMethod();if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {// source对象对应的的属性PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {Method readMethod = sourcePd.getReadMethod();if (readMethod != null) {ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);// Ignore generic types in assignable check if either ResolvableType has unresolvable generics.boolean isAssignable =(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :targetResolvableType.isAssignableFrom(sourceResolvableType));if (isAssignable) {try {// 设置成可访问,防止私有if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 赋值Object value = readMethod.invoke(source);if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}writeMethod.invoke(target, value);}catch (Throwable ex) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);}}}}}}}

然后这里我们可以看到它最后也是通过反射的invoke方法来进行set设置值,而value是从之前的source获取,所以获取的是它的引用,所以用的是浅引用。

浅拷贝和深拷贝

浅拷贝从上面的例子应该是非常容易就可以理解了,就是浅拷贝除了拷贝基础数据类型及其包装类型外,在对引用类型的拷贝时是直接拷引用,在Java中就是相当于是同一个的对象的引用。

深拷贝的话就是相当于创建一个新的一模一样的对象,但是这个对象的内存地址是不一致的。

在Java里面实现深拷贝的方式有三种。

  • 通过直接创建赋值,set

  • 通过序列化和反序列化创建的对象是属于重新生成的对象,也是属于深拷贝。

  • 通过fastjson这样的json反序列化也是实现深拷贝的一种方式。

  • 通过实现重写父类的clone方法也可以实现。

借此记录下自己踩到的BUG,虽然不是很难的东西,写出来也是希望下一次遇到这个问题的时候能够更快的解决!

http://www.yayakq.cn/news/242311/

相关文章:

  • 公司的个人网站怎么做建设银行网站信息补充
  • 怎么找网站做公示免费自助建站网站一览自助建网站
  • 企业网站建设与管理作业大连百度推广
  • 任丘市网站建设公司网站管理系统怎么用
  • 国际物流网站建设创建站怎么上传网站怎么办
  • 网站建设承诺在门户网站管理建设工作讲话
  • 网上超市网站的设计与实现企业做网站需要什么
  • h5响应式网站模板产品设计在线
  • 网站建设维护预算wordpress怎样弄栏目
  • Godaddy优惠码网站怎么做的网页制作与设计知识点复习
  • 网站开发怎么做wordpress使用redis
  • 免费建立教育网站wordpress运营
  • 个人建站免费服务器广州网站定制开发方案
  • 万和城网站哈尔滨网站建设自助建站
  • 手机网站开发设计报价单网站开发ceil(5.5)
  • 凡科建站的怎么取消手机网站软件是如何开发的
  • 网站建设时如何建立客户信赖感wordpress插件外贸
  • 找人做网站去哪里找做网站关键词软件
  • 昆山专业网站建设公司哪家好网站建设与维护工作内容
  • 黄石网站建网站制作公司套路
  • 微信的微网站做网站导航一般字号是多少
  • 个人网站建设价格表如何做wordpress文章页
  • 网站如何留住用户企业logo设计说明
  • 房产集团网站建设好的ui设计培训学校
  • 如何让百度收录网站网站开发工程师的证件
  • 深圳做网站好的公司盐城大丰网站建设找哪家好
  • wordpress怎么建立网站网络推广公司是做什么的
  • 服装商务网站建设策划书郑州网站建设哪家公司便宜
  • 我自己的网站 怎样做防火墙西安大公司
  • 网站开发php和c语言区别手机网站页面如何制作软件