Java OOP中对象操作ArrayList时状态同步异常问题求助
问题描述
在Java面向对象编程中操作对象内的ArrayList时遇到问题:不同对象本该持有集合的不同元素子集,但最终都采用了ArrayList的最终状态。
具体场景:创建ArrayList并添加元素后,调用lilnas.setAlbuns(albuns)赋值;移除集合首个元素后,再调用filipe.setAlbuns(albuns)赋值。但最终两个对象的ArrayList均为移除元素后的状态。
示例代码
主逻辑代码
ArrayList<Album> albuns = new ArrayList<Album>(); Collections.addAll(albuns, folclore, sedimentar,angry,sick,hungry,fever,fast,slow,happy,sad); lilnas.setAlbuns(albuns); albuns.remove(0); filipe.setAlbuns(albuns);
setAlbuns方法代码
public void setAlbuns(ArrayList<Album> albuns){ this.albuns = albuns; }
结果展示
Filipe albums:
Sedimentar - 07/04/2023 - gravado - South Park Angry - 07/07/2020 - Ao vivo - Quicks Sick - 30/11/2015 - gravado - Batman Hungry - 05/12/2019 - gravado - Flash Fever - 05/03/2015 - gravado - Batman Fast - 10/03/2020 - Ao vivo - Quicks Slow - 07/07/2010 - gravado - North park Happy - 04/09/2010 - gravado - North Park Sad - 11/06/2019 - gravado - Flash
Lilnas albums:
Sedimentar - 07/04/2023 - gravado - South Park Angry - 07/07/2020 - Ao vivo - Quicks Sick - 30/11/2015 - gravado - Batman Hungry - 05/12/2019 - gravado - Flash Fever - 05/03/2015 - gravado - Batman Fast - 10/03/2020 - Ao vivo - Quicks Slow - 07/07/2010 - gravado - North park Happy - 04/09/2010 - gravado - North Park Sad - 11/06/2019 - gravado - Flash
原因分析
Java中对象是引用传递,当前的setAlbuns方法只是将传入的ArrayList引用直接赋值给对象的成员变量。这意味着lilnas和filipe的albuns成员指向的是同一个ArrayList实例,后续对该集合的任何修改(比如remove(0))都会同时影响两个对象的集合状态。
解决方案
1. 传递集合的浅拷贝(最常用)
修改setAlbuns方法,在赋值时创建新的ArrayList实例,将原集合的元素复制进去:
public void setAlbuns(ArrayList<Album> albuns){ this.albuns = new ArrayList<>(albuns); }
或者在调用setAlbuns时直接传入集合副本:
ArrayList<Album> albuns = new ArrayList<>(); Collections.addAll(albuns, folclore, sedimentar,angry,sick,hungry,fever,fast,slow,happy,sad); // 给lilnas传入副本 lilnas.setAlbuns(new ArrayList<>(albuns)); albuns.remove(0); // 给filipe传入修改后的副本 filipe.setAlbuns(new ArrayList<>(albuns));
这种方式是浅拷贝,如果Album对象本身是不可变的,或者不需要修改Album实例,完全满足需求。
2. 使用不可变集合(适用于不需要修改集合的场景)
如果对象的集合不需要后续修改,可以使用不可变集合来避免意外修改:
ArrayList<Album> albuns = new ArrayList<>(); Collections.addAll(albuns, folclore, sedimentar,angry,sick,hungry,fever,fast,slow,happy,sad); lilnas.setAlbuns(Collections.unmodifiableList(new ArrayList<>(albuns))); albuns.remove(0); filipe.setAlbuns(Collections.unmodifiableList(new ArrayList<>(albuns)));
注意:不可变集合无法被修改,若对象需要修改自己的集合,此方式不适用。
3. 深拷贝(适用于Album为可变对象的场景)
如果Album是自定义的可变类,且需要每个对象的Album实例也完全独立,需要实现深拷贝:
首先给Album添加拷贝构造函数:
public class Album { // 成员变量 private String name; private String date; // 其他成员... // 拷贝构造函数 public Album(Album other) { this.name = other.name; this.date = other.date; // 复制其他成员变量,引用类型需递归拷贝 } }
然后修改setAlbuns方法,逐个拷贝Album实例:
public void setAlbuns(ArrayList<Album> albuns){ this.albuns = new ArrayList<>(); for(Album album : albuns){ this.albuns.add(new Album(album)); } }
内容的提问来源于stack exchange,提问作者Vinícius Eduardo Lima Lodi

