Java 复制对象数组,然后在不影响副本的情况下修改原始对象

Java 复制对象数组,然后在不影响副本的情况下修改原始对象,java,arrays,object,copy,Java,Arrays,Object,Copy,所以我一直在为这个看似无关紧要的问题绞尽脑汁。我不一定知道要找什么。我到处寻找解决办法。我需要做一个2D数组的副本。数组由对象(我创建的一个类调用单元)组成,但一旦我创建了一个副本,我就会将该副本存储到一个哈希映射中(供以后参考),然后继续修改原始数组。问题是对原始文件的修改也会影响哈希映射中的副本。基本上,在一天结束时,我的哈希映射将由同一网格的多个版本组成。我尝试过array.clone()、System.arraycopy(…)、Arrays.copyof()、传统的for循环复制方案。。

所以我一直在为这个看似无关紧要的问题绞尽脑汁。我不一定知道要找什么。我到处寻找解决办法。我需要做一个2D数组的副本。数组由对象(我创建的一个类调用单元)组成,但一旦我创建了一个副本,我就会将该副本存储到一个哈希映射中(供以后参考),然后继续修改原始数组。问题是对原始文件的修改也会影响哈希映射中的副本。基本上,在一天结束时,我的哈希映射将由同一网格的多个版本组成。我尝试过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
}
静态单元格[][]gridCopy;
...
单元格[][]网格=getGrid(文件)//从文件中获取网格(如果您必须知道,这是数独游戏)
...
静态布尔数独(单元格网格[])
{
//如果没有未分配的位置,我们就完成了
if(未分配==null)
返回true;//成功!
int行=unassigned.row;
int col=unassigned.col;
ArrayList域=未分配的.domain;
/考虑数字1至9
对于(int num=0;num
您正在创建对象的浅层副本。Array.clone()将仅适用于基本类型。您应该在试图复制的对象类中创建一个方法,该方法创建并返回具有相同属性值的类的新实例。然后,您可以在数组中循环获取每个对象的副本,并将它们添加到新数组中,然后将新数组存储到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;
    }
}

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

如果您只是说修改原始数组,那么Arrays.copyof(…)就足够了,因为它会创建一个新数组(事实上并不相同),但我猜当您提到“修改原始数组”时,您指的是修改其中引用的对象(而不是数组本身)

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

使用,您可以很容易地这样做(在本例中,在实现克隆方法之后):

YourClass[]originalArray=newyourclass[]{…};
YourClass[]arrayCopy=Collections2.transform(Arrays.asList(originalArray),新函数(){
@可空
@凌驾
公共对象应用(YourClass anObject){
返回anObject.clone();
}
}).toArray();
或者,如果您不想产生不必要的开销,必须先转换为集合,然后再转换回数组,那么可以使用我实现的这段小代码(它也使用Guava,但只使用Function类):


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

虽然不是答案,但要理解为什么您尝试深度复制不起作用,请查看gridCopy
静态单元格[]gridCopy的静态声明
在嵌套的
for
循环中,您正在将新单元对象复制到相同的静态二维数组中。结果是,状态堆栈中的所有引用都指向二维数组的同一静态实例。要修复此问题,只需将gridCopy设置为非静态,并在每次执行复制时创建它的新实例。
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();