复制对象数组,然后修改原始对象而不影响副本

时间:2014-11-25 20:32:42

标签: java arrays object copy

所以我一直在为这个看似微不足道的问题敲打我的脑袋。我不一定知道要搜索什么。我四处寻找解决方案。我需要复制二维数组。该数组由对象(我创建的一个类调用Cell)组成,但是只要我创建一个副本,我就将该副本存储到一个哈希映射中(以后可能参考),然后继续修改原始数组。问题是对原始的修改也会影响哈希映射中的副本。基本上在一天结束时,我的哈希映射将包含同一网格的许多版本。我已经尝试过array.clone(),System.arraycopy(...),Arrays.copyof(),传统的for循环复制方案....最后我意识到我需要所谓的深拷贝,你复制的地方每个对象的每个数据字段都成为一个新的对象到数组副本中....是的,那也没有用。看看:

static Cell[][] gridCopy;
...
Cell[][] grid = getGrid(file); //get grid from a file (this is Sudoku if you must know)
...
static boolean SolveSudoku(Cell grid[][])
{
// If there is no unassigned location, we are done
    if (unassigned == null)
        return true; // success!

    int row = unassigned.row;
    int col = unassigned.col;
    ArrayList<Integer> domain = unassigned.domain;

    // consider digits 1 to 9
    for (int num = 0; num < domain.size(); num++)
    {
        //if looks promising
        if (isSafe(grid, row, col, domain.get(num)))
        {
            //gridCopy = new Cell[N][N];
            instance++;
            // make tentative assignment
            grid[row][col].value = domain.get(num);

            //here is my attempt at a deep copy
            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    gridCopy[i][j] = new Cell(grid[i][j].row, grid[i][j].col, grid[i][j].value, grid[i][j].domain);
            states.put(instance, gridCopy); //save the current state in a map for reference if we backtrack

            //as soon as I change things here in the original, the copy in the 'states' map also changes
            updateSpecifiedDomains(grid, row, col, domain.get(num), true);

            printGrid(grid, "Instance" + String.valueOf(instance));

            // return, if success, yay!
            if (SolveSudoku(grid, choice))
                return true;

            // failure, un-assign & try again
            //int temp = grid[row][col].value;
            grid = states.get(instance); //retain previous state
            grid[row][col].value = UNASSIGNED;

            /*updateSpecifiedDomains(grid, row, col, temp, false);
            while (domain.contains(temp))
                grid[row][col].domain.remove((Integer)temp);*/

            //domain.remove((Integer)num);
        }
    }
    count++;
    instance--;
    return false; // this triggers backtracking
}

3 个答案:

答案 0 :(得分:2)

您正在创建对象的浅表副本。 Array.clone()仅适用于基本类型。您应该在要复制的对象的Class中创建一个方法,该方法创建并返回具有相同属性值的类的新实例。然后你可以遍历你的数组获取每个对象的副本并将它们添加到一个新数组,然后将新数组存储到你的hashmap。

示例:

public class MyClass()
{
    private String temp;

    public MyClass(String temp)
    {
        this.temp = temp;
    }

    public MyClass copy()
    {
       MyClass copy = new MyClass(this.temp);
       //set attributes in constructor or using setters so they are the same as this object
       return copy;
    }
}

答案 1 :(得分:0)

java中的所有内容都是指针。这意味着复制数组就像你实现它一样,creata确实是一个指向新数组的指针,但是数组中的元素指向旧数组中的元素,因此通过方法修改它们会影响两个数组。 为了不发生这种情况,您必须实现深度克隆机制来克隆原始数组的元素,并将新创建的克隆插入到新数组中。修改克隆不会影响原始元素,因为它们指向堆中的不同地址。

答案 2 :(得分:0)

如果你只是在谈论修改原始数组,那么Arrays.copyof(...)应该足够了,因为它创建了一个新的数组(确实不一样),但是当你提到时,我猜测&#34;修改原文&#34;,你指的是修改它中引用的对象(不是数组本身)。

因此,您首先需要为每个对象实现复制构造函数或复制方法,然后迭代数组并将对象复制到新数组中。

使用Guava,您可以轻松地执行此操作(在此示例中,将在实现克隆方法之后):

YourClass [] originalArray = new YourClass[]{...};
YourClass [] arrayCopy = Collections2.transform(Arrays.asList(originalArray), new Function<YourClass, YourClass>() {
    @Nullable
    @Override
    public Object apply(YourClass anObject) {
        return anObject.clone();
    }
}).toArray();

或者,如果你不想要转换到Collection然后回到数组​​的不必要的开销,你可以使用我实现的这个小代码(它也使用Guava,但只是Function类): Transform a Generic Array Efficiently Using Guava

最后,我必须说您可以根据具体需要以不同方式实现复制构造函数或复制方法(或克隆,或任何您可能想要调用的方法):Deep copy, shallow copy, clone