复制构造函数创建依赖副本

时间:2013-07-17 14:49:57

标签: java clone copy-constructor

我实现了复制构造函数,如here所述。但问题仍然是当我更新route_copy时,相同的更新将应用于route。所以,我不明白我的代码有什么问题?

public class Route implements Comparable<Route> {
    private List<Site> sites;

    public Route()
    {
        sites = new ArrayList<Site>();
    }

    public Route(List<Site> sites)
    {
        this.sites = sites;
    }

    /**
     * Copy constructor
     */
    public Route(Route r) {
        this(r.sites);
    }

    public void deleteSite(Site s) {
        this.sites.remove(s);
    }
}

public processData(Route route)
{
  Route route_copy = new Route(route);
  Site s = selectSite(route_copy);
  route_copy.deleteSite(s); // !!! now 'route' does not contain an  element 's'
}

5 个答案:

答案 0 :(得分:5)

在你的拷贝构造函数中,你只是做一个浅拷贝,而你需要做一个深层拷贝:

public Route(Route r) {
    this(r.sites);
}

在这里,您仍在复制list的引用,该引用仍然指向相同的ArrayList。您应该修改它以创建列表的副本。可能,您还需要在arraylist中创建元素的副本,如下所示:

public Route(Route r) {
    List<Site> newSites = new ArrayList<Site>();

    for (Site obj: r.sites) {
        // Add copy of obj to the newSites
        // So you need yet another copy constructor in 'Site' class.
    }

    this.sites = newSites;
}

查看此帖子 - Shallow Copy vs Deep Copy.

答案 1 :(得分:2)

你的&#34;复制构造函数&#34;没有制作输入列表的副本。尝试像

这样的东西
public Route(List<Site> sites)
{
    this.sites = new ArrayList<Site>(sites);
}

为你的第二个构造函数。

答案 2 :(得分:2)

当然,它会创建依赖副本,也称为副本。

您需要深度副本。

答案 3 :(得分:2)

问题是两个列表仍然指向相同的内存位置,因此,一个列表上的任何操作最终都会修改另一个列表。

您可以尝试使用ArrayList的复制构造函数:

  

public ArrayList(Collection c)

     

构造一个列表   包含指定集合的​​元素,按顺序排列   由集合的迭代器返回。

像这样:

     public Route(Route r) {
     this(new ArrayList<Site>(r.sites));
     }

但是请注意,对列表中的Site个对象进行任何修改可能会对其他列表中存储的其他对象产生重复,具体取决于Site对象的复杂程度。

答案 4 :(得分:1)

你使用复制构造函数做的只是让新Route使用旧Route的列表,因此对其中一个的任何更改都会立即影响另一个

您需要做的是让复制构造函数创建一个新列表:

sites = new ArrayList<Site>(oldList);