从对象返回嵌套集合的正确方法是什么?

时间:2014-01-26 10:43:43

标签: 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;
  }

OR

  //Implementation # 3
  public List<Address> getAddresses(){
    return addresses; //i.e return the original list.
  }

现在,我发现我不应该使用第三个实现,因为我不想让一些外部代码更改Person对象的地址。

在第一和第二之间,我有点困惑。前两个实现中哪一个是首选,特别是当我将有某种数据存储/数据库来存储所有人物对象时?

我想知道何时使用Implementation # 1以及何时使用Implementation # 2

3 个答案:

答案 0 :(得分:2)

一般情况下,如果AddresssetValue,您应该使用实现#1;否则,实现#2将正常工作,因为您的Address对象是不可变的。

请注意,即使Address本身是可变的,您也不一定要使用更昂贵的解决方案#1。另一种方法是将可变Address实例作为不可变接口呈现,并返回实现该接口的对象列表。这样可以避免复制单个对象:

public interface Address {
    String getAddress();
}
class AddressImpl implements Address {
    String address;
    public AddressImpl(String address){
        this.address = address;
    }
    public String getAddress() { return address; }
    public void setAddress(String address) { this.address = address; }
}
...
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;
}

答案 1 :(得分:1)

其他答案中已经提到了Address类的可变性/不变性的(重要)方面。

您已经提到过,通常不应该使用第三个实现(返回原始列表),以防止外部代码修改列表。但是,这个目标也可以通过创建一个不可修改的视图来实现:

//Implementation #4
/**
 * Returns an unmodifiable view on the list of addresses
 * ...
 */
public List<Address> getAddresses(){
  return Collections.unmodifiableList(addresses);
}

请注意,评论可能很重要:当某人在列表中收到不可修改的视图时,他必须假设支持列表可能会在他持有对此视图的引用时发生更改。

不幸的是,在“隐藏实现细节”和“精确指定方法”之间存在轻微的权衡......

答案 2 :(得分:0)

也许:

List<String> list = new ArrayList();
List<String> listCopy = new ArrayList(list);

listCopy将独立于list