记一个使用List<Object>复制的坑
问题经过:
有一个需求,需要返回结果组成装成Map<String,List<Object>>这种格式,Map的可以就是字符串没啥问题,后面是一个集合,我在组装数据时重复使用到了一个List<Object>作为基础集合,然后遍历重新new 出新的集合将基础集合addAll到新集合中,后续又对新集合进行了修改 操作,然后匠心机和填充到结果Map中。
代码大体是大概是这样:
Map<String,List<Object>> mapList = new HashMap<>();
List<Object> baseList = new ArrayList();//基础集合,当然这里面可能有基础数据
for(int i= 0;i<10;i++){
List<Object> newList = new ArrayList();
newList.addAll(baseList);
newList.forEach(t->{
//修改操作
})
mapList.put("1",newList);
}
出现的问题:
结果集合中的数据全部相同,且为最后一次修改的数据
写了个小示例:
static class Student{
private String username;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
for (int i=0;i<3;i++){
Student stu = new Student();
stu.setAge(i);
stu.setUsername("Test"+i);
list.add(stu);
}
List<Student> list1 = new ArrayList<>();
list1.addAll(list);
list.forEach(t->{
log.info("集合list:{}",JSON.toJSON(t));
});
list1.forEach(t1->{
log.info("集合list1:{}",JSON.toJSON(t1));
});
list1.forEach(t->{
if (t.getUsername().equals("Test0")){
t.setAge(99);
}
});
log.info("========================================");
list.forEach(t->{
log.info("集合list:{}", JSON.toJSON(t));
});
list1.forEach(t1->{
log.info("集合list1:{}",JSON.toJSON(t1));
});
}
打印结果:两个集合中的对象都被改掉
问题排查:
一开始我想到的是,我明明new了一个新的集合进行填充应该不会有问题,很奇怪,仔细查看数据发现集合的数据相同且为最后一次的数据,发现集合被覆盖,但是考虑到是new的新集合。
首先考虑的是addAll()这个方法是不是只复制了集合的地址导致的,然后又换成了循环填充还是不行,查阅资料后发现addAll()就是填充的新集合。
经debug发现集合中的对象地址是一致的。。。。。,恍然大悟
结果:
在集合复制的时候应首先拷贝其中的对象元素到新集合中,不然相当于所有集合中的对象地址指向的是一个,所以修改当然一起都改。。。。
可以使用:hutool包中的这个方法进行对象拷贝:
BeanUtil.copyProperties("源对象","目标对象");
犯如此低低级之错误实属不应该,吃一堑长一智吧!!!!