Java修改某List内对象时另一List同引用对象同步变更问题
问题原因
Java中对于非基本类型的对象,所有赋值、参数传递都是引用传递。你代码中往newList添加的data并不是独立的新对象,而是和oldList中对应元素指向同一块内存地址的引用。后续不管通过哪个引用修改对象的属性,两个列表读取到的都是同一个内存地址里的最新值,自然会出现同步变更的现象。调整代码执行顺序(比如先add再修改原对象)无法解决这个问题,本质原因是两个列表持有的是同一个对象的引用。
实现方案
核心思路是:在将对象加入newList时,存入当前对象状态的深拷贝副本,让newList持有的是独立内存地址的新对象,后续修改oldList中的原对象就不会影响到newList里的副本。
最推荐的实现方式是为Data类添加拷贝构造方法,代码可读性和可维护性最高:
- 首先在
Data类中实现拷贝构造逻辑,逐字段复制属性值生成新实例:
public class Data { // 类的原有属性定义,示例: private String value; private String anotherProp; // 拷贝构造方法 public Data(Data source) { // 逐字段复制值,如果属性是自定义引用类型,需要对应调用该类型的拷贝方法生成新实例,避免浅拷贝问题 this.value = source.value; this.anotherProp = source.anotherProp; } // 类原有setter、getter及其他业务方法 public void setvalue(String value) { this.value = value; } public void setAnother() { // 原有业务逻辑 } }
- 修改原有循环逻辑,在add时传入拷贝生成的新对象:
List<Data> oldList = // 初始化原列表 List<Data> newList = // 初始化新列表 for (Data data : oldList) { if (condition) { data.setvalue(""); // 加入新列表的是独立的拷贝副本,和原对象无引用关联 newList.add(new Data(data)); // 后续修改原对象,不会影响newList中存储的副本 data.setAnother(); } }
如果不方便修改Data类的源码,也可以在循环中手动创建新实例、逐字段赋值后再加入newList,逻辑和拷贝构造一致,适合属性少、临时使用的场景:
for (Data data : oldList) { if (condition) { data.setvalue(""); Data copyInstance = new Data(); // 逐一把需要保留的属性赋值到新实例 copyInstance.setvalue(data.getValue()); newList.add(copyInstance); data.setAnother(); } }
注意事项
- 不推荐直接使用
Object类的clone()方法做拷贝,其默认实现是浅拷贝,如果Data类包含自定义引用类型属性,内层对象依然会存在引用共享问题,且该方法的使用约束较多,容易引入隐藏bug。 - 如果
Data类的属性包含其他自定义对象类型,做拷贝时需要给这些属性的类型也实现对应的拷贝逻辑,完成完整的深拷贝,否则内层属性依然会出现同步修改的问题。
内容的提问来源于stack exchange,提问作者Raghavendra R.V
相关产品推荐
相关产品推荐

