java从对象返回嵌套集合的正确方法是什么?
假设我有下面的课程
class Person{
long id;
List<Address> addresses;
public Person(long id){
this.id = id;
this.addresses = new ArrayList<Address>();
}
public long getId(){
return id;
}
//Implementation # 1
public List<Address> getAddresses(){
List<Address> addressesToReturn = new ArrayList<Address>();
for(Address address : addresses){
addressesToReturn.add(address.copy());
}
return addressesToReturn;
}
}
class Address{
String value;
public Address(String value){
this.value = value;
}
public Address copy(){
Address address = new Address(this.value);
return address;
}
}
在这种特殊情况下,getAddresses()
返回地址对象的副本列表。我可以有两种替代实现,如下所示:
//Implementation # 2
public List<Address> getAddresses(){
List<Address> addressesToReturn = new ArrayList<Address>();
for(Address address : addresses){
addressesToReturn.add(address); //i.e. return the original object as is
}
return addressesToReturn;
}
或
//Implementation # 3
public List<Address> getAddresses(){
return addresses; //i.e return the original list.
}
现在,我看到我不应该使用第三个实现,因为我不希望一些外部代码更改Person对象的地址
在第一个和第二个之间,我有点困惑。首选前两种实现中的哪一种,尤其是当我将使用某种数据存储/数据库来存储所有person对象时
我想知道什么时候使用Implementation # 1
和什么时候使用Implementation # 2
# 1 楼答案
也许:
listCopy
将独立于list
# 2 楼答案
其他答案中已经提到了
Address
类的可变性/不变性的(重要)方面您已经提到,通常不应使用第三个实现(返回原始列表),以防止外部代码修改列表。但这一目标也可以通过创建不可修改的视图来实现:
请注意,注释可能很重要:当某人收到列表上不可修改的视图时,他必须假设支持列表可能会更改,同时他持有对该视图的引用
不幸的是,在“隐藏实现细节”和“精确地指定方法”之间有一个小小的权衡
# 3 楼答案
一般来说,如果
Address
有setValue
,那么应该使用实现#1;否则,实现#2可以正常工作,因为Address
对象是不可变的注意,即使
Address
本身是可变的,您也不一定要使用更昂贵的解决方案#1。另一种方法是将可变的Address
实例表示为不可变接口,并返回实现该接口的对象列表。这样可以避免复制单个对象: