浅拷贝:只对基本数据类型进行拷贝,对于引用数据类型只是进行了引用的传递,没有真实的创建一个新的对象,则是浅拷贝;(参数引用传递中的改变源对象情况)
深拷贝:在对引用数据类型拷贝过程中,创建了一个新的对象,并且复制了对象内的所有成员变量,则是深拷贝(参数引用传递中的不改变源对象情况)
Cloneable 接口,并覆写 clone() 方法,clone()方法实现的是对当前对象进行拷贝。
将对象写入到io流中,反序列化是从io流中恢复对象;
问:当一个对象当作参数传递到一个方法之后,此方法可以改变对象属性,并且可以返回变化后的对象,那么这里是值传递还是对象传递。。
答:java中只有值传递参数
刚工作的时候,业务代码开发过程中遇到过这种直接修改了引用数据类型参数导致的数据异常问题。
有问题的代码如下:
public SettingsExtVo filterRateByCity(SettingsExtVo settingsExtVo,String cityCode){if (cityCode == null){return settingsExtVo;}List groups = settingsExtVo.getGroups();// SettingsExtVo settingsExtVoNew = new SettingsExtVo();// 定义一个新的ListList groupExtVOList = com.google.api.client.util.Lists.newArrayList();// 遍历groups筛选出满足城市条件的groupgroups.forEach(groupExtVO -> {if (groupExtVO.getCondition() != null){Map condition = groupExtVO.getCondition();if (condition.get("cityGuid") != null){List cityList = Arrays.asList(condition.get("cityGuid").split(","));if (cityList.contains(cityCode)){groupExtVOList.add(groupExtVO);}}}});if (CollectionUtils.isEmpty(groupExtVOList)){groups.forEach(groupExtVO1 -> {if (groupExtVO1.getCondition() == null){groupExtVOList.add(groupExtVO1);}});}// 修改引用传参数,值传递传的是对象地址值,此时对地址对应的对象进行了修改。settingsExtVo.setGroups(groupExtVOList);return settingsExtVo;}
上述代码功能主要是对一个对象中的list列表数据进行筛选,并且返回筛选后的数据。
代码中对SettingsExtVo的实例对象进行了修改,而该对象是本地缓存的数据对象,通过该方法对本地缓存的对象进行修改,这就导致后续程序使用该缓存对象的时候出现数据丢失的问题。
修复后的代码逻辑(使用json序列化,深拷贝出一个全新的对象)
/*** 根据头盔城市筛选出对应的评价问题** @param settingsExtVo* @param cityCode* @return SettingsExtVo*/public SettingsExtVo filterRateByCity(SettingsExtVo settingsExtVo,String cityCode){// 利用Json序列化实现对象深拷贝String jsonString = JsonUtils.json2String(settingsExtVo);SettingsExtVo settingsExtVoNew = JsonUtils.json2Object(jsonString,SettingsExtVo.class);List groups = settingsExtVo.getGroups();// 定义一个新的ListList groupExtVOList = Lists.newArrayList();// 遍历groups筛选出满足城市条件的groupgroups.forEach(groupExtVO -> {if (groupExtVO.getCondition() != null && cityCode != null){Map condition = groupExtVO.getCondition();if (condition.get("cityGuid") != null){List cityList = Arrays.asList(condition.get("cityGuid").split(","));if (cityList.contains(cityCode)){groupExtVOList.add(groupExtVO);}}}});if (CollectionUtils.isEmpty(groupExtVOList)){groups.forEach(groupExtVO1 -> {if (groupExtVO1.getCondition() == null){groupExtVOList.add(groupExtVO1);}});}settingsExtVoNew.setGroups(groupExtVOList);return settingsExtVoNew;}
第二种修复方案是不修改引用参数对象,利用参数对象做筛选,但是新建一个对象来存储筛选的数据,并且也返回这个新创建的对象;
/*** 按照group的匹配规则来筛选评价问题* @param settingsExtVo* @param cityCode* @return*/public List filterRateByCondition(SettingsExtVo settingsExtVo,String cityCode,String npsType){List groups = settingsExtVo.getGroups();// 定义一个新的ListList groupExtVOList = Lists.newArrayList();//遍历groups筛选出满足头盔城市条件的groupgroups.forEach(groupExtVO -> {if (groupExtVO.getCondition() != null && cityCode != null){Map condition = groupExtVO.getCondition();if (condition.get("cityGuid") != null){List cityList = Arrays.asList(condition.get("cityGuid").split(","));if (cityList.contains(cityCode) && groupExtVO.getDisplay().equals(true)){groupExtVOList.add(groupExtVO);}}}});// 按头盔城市筛选为空,则再次按照nps模式进行筛选if (CollectionUtils.isEmpty(groupExtVOList)){groups.forEach(groupExtVO -> {if (groupExtVO.getCondition() != null && Objects.nonNull(npsType)){if (groupExtVO.getCondition().get("npsType").equals(npsType)){groupExtVOList.add(groupExtVO);}}});}// 如果按照已有规则筛选都为空,则筛选无规则groupif (CollectionUtils.isEmpty(groupExtVOList)){groups.forEach(groupExtVO1 -> {if (Objects.isNull(groupExtVO1.getCondition())){groupExtVOList.add(groupExtVO1);}});}return groupExtVOList;}