有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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


共 (3) 个答案

  1. # 1 楼答案

    也许:

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

    listCopy将独立于list

  2. # 2 楼答案

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

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

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

    请注意,注释可能很重要:当某人收到列表上不可修改的视图时,他必须假设支持列表可能会更改,同时他持有对该视图的引用

    不幸的是,在“隐藏实现细节”和“精确地指定方法”之间有一个小小的权衡

  3. # 3 楼答案

    一般来说,如果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;
    }