开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
背景
开发的时候,需要对数据进行不同的操作,特别是对同一组数据进行多次操作时,如果没有注意数据隔离就容易出现bug。
案例
一个数组中有三个人的信息,要重复操作给这三个人编号,把新数据存到新的数组中,然后问题就来了。
@Test
public void test4() {
Random r = new Random();
List<Map<String, Object>> l = new ArrayList<>();
List<Map<String, Object>> l1 = new ArrayList<>();
Map<String, Object> m = new HashMap<>();
m.put("name", "张三");
Map<String, Object> m1 = new HashMap<>();
m1.put("name", "李四");
Map<String, Object> m2 = new HashMap<>();
m2.put("name", "王五");
l1.add(m);
l1.add(m1);
l1.add(m2);
for (int i = 0; i < 3; i++) {
for (Map<String, Object> b : l1) {
int t = r.nextInt(1000);
b.put("分数", t);
System.out.println(t);
}
l.addAll(l1);
}
System.out.println(l);
}
输出结果:
403
134
865
259
882
491
112
950
714
[{分数=112, name=张三}, {分数=950, name=李四}, {分数=714, name=王五}, {分数=112, name=张三}, {分数=950, name=李四}, {分数=714, name=王五}, {分数=112, name=张三}, {分数=950, name=李四}, {分数=714, name=王五}]
尽管每次插入的随机数不同,但是发现结果是重复的,因为循环操作了同一个数组l1,而数组l中保存的是l1的地址(l.addAll(l1);)导致最后的结果是3组相同的数据。所以我们需要新建一个数组l2去接收数组l1的数据,每次操作新数组,实现数据隔离。
方案一:List.addAll()(浅拷贝无效)
List<Map<String, Object>> l2 = new ArrayList<>();
l2.addAll(l1);
方案二:使用List的构造方法(浅拷贝无效)
List<Map<String, Object>> l2 = new ArrayList<>(l1);
两种方案输出结果还是重复的数据
[{分数=447, name=张三}, {分数=806, name=李四}, {分数=212, name=王五}, {分数=447, name=张三}, {分数=806, name=李四}, {分数=212, name=王五}, {分数=447, name=张三}, {分数=806, name=李四}, {分数=212, name=王五}]
打印JSONObject.toJSONString()打印结果会发现还是相同的地址引用
System.out.println(JSONObject.toJSONString(l));
结果:
[{"分数":413,"name":"张三"},{"分数":206,"name":"李四"},{"分数":279,"name":"王五"},{"$ref":"$[0]"},{"$ref":"$[1]"},{"$ref":"$[2]"},
{"$ref":"$[0]"},{"$ref":"$[1]"},{"$ref":"$[2]"}]
方案三:数据类型转换(深拷贝)
@Test
public void test6() {
Random r = new Random();
List<Map<String, Object>> l = new ArrayList<>();
List<Map<String, Object>> l1 = new ArrayList<>();
Map<String, Object> m = new HashMap<>();
m.put("a", "1");
Map<String, Object> m1 = new HashMap<>();
m1.put("a", "2");
l1.add(m);
l1.add(m1);
for (int i = 0; i < 3; i++) {
// 方案三,转成String,在转回List
String str = JSONObject.toJSONString(l1);
List<Map<String, Object>> l2 = JSONObject.parseObject(str, List.class);
for (Map<String, Object> b : l2) {
int t = r.nextInt(1000);
b.put("c", t);
System.out.println(t);
}
l.addAll(l2);
}
System.out.println(l);
}
测试发现数据没有重复,实现数据隔离
941
685
901
129
449
516
[{"a":"1","c":941}, {"a":"2","c":685}, {"a":"1","c":901}, {"a":"2","c":129}, {"a":"1","c":449}, {"a":"2","c":516}]
当然还有其他序列化方式的深度拷贝都能实现数据隔离,之后再补充