Java 使用Object.clone()时出现错误

Java 使用Object.clone()时出现错误,java,clone,Java,Clone,我有下一个场景: 我在主类中定义了一个int[][]变量int[][]matrix1=newint[10][10]我给它一些值。然后调用一个方法,并将此变量作为参数发送给该方法。作为一个对象,它发送的是引用而不是值,因此在方法内部,因为我必须更改matrix1包含的值,但在对象从方法返回后不会影响该对象,所以我对其进行了如下克隆: private void myMethod( int[][] matrix1 ) { int[][] matrix1Clone = matrix1.clone

我有下一个场景:

我在主类中定义了一个
int[][]
变量
int[][]matrix1=newint[10][10]
我给它一些值。然后调用一个方法,并将此变量作为参数发送给该方法。作为一个对象,它发送的是引用而不是值,因此在方法内部,因为我必须更改matrix1包含的值,但在对象从方法返回后不会影响该对象,所以我对其进行了如下克隆:

private void myMethod( int[][] matrix1 )
{
    int[][] matrix1Clone = matrix1.clone();
    //And next i do some changes to matrix1Clone
    ......
}
但问题是我对matrix1Clone所做的更改也发生在matrix1中。所以它并没有真正创建matrix1对象的克隆,但两个变量都指向同一个对象

为什么会这样?我似乎不明白。为什么克隆方法不起作用

如果您需要更多信息,请询问。但我恐怕这就是问题所在,我不能给你更多,但也许我可以试试

我可能错过了什么,但我不知道是什么

谢谢

编辑


对不起,我打错了。天晚了,我累了。我确实在使用克隆方法,这就是为什么我感到困惑,因为它不起作用:(。

你给出的
matrix1Clone
matrix1
相同。如果你改变
matrix1Clone
,那么
matrix1
也会改变

您可以通过迭代源数组来复制数组:

   public static int[][] clone2DArray(int[][] array) {
        int rows = array.length;

        //clone the 'shallow' structure of array
        int[][] newArray = array.clone();
        //clone the 'deep' structure of array
        for(int row = 0; row < rows; row++){
            newArray[row] = array[row].clone();
        }

        return newArray;
    }
publicstaticint[]]clone2DArray(int[]]array){
int rows=array.length;
//克隆阵列的“浅”结构
int[]newArray=array.clone();
//克隆阵列的“深层”结构
对于(int row=0;row
您提供的
matrix1Clone
参考与
matrix1
相同。如果您更改
matrix1Clone
,则
matrix1
也会更改

您可以通过迭代源数组来复制数组:

   public static int[][] clone2DArray(int[][] array) {
        int rows = array.length;

        //clone the 'shallow' structure of array
        int[][] newArray = array.clone();
        //clone the 'deep' structure of array
        for(int row = 0; row < rows; row++){
            newArray[row] = array[row].clone();
        }

        return newArray;
    }
publicstaticint[]]clone2DArray(int[]]array){
int rows=array.length;
//克隆阵列的“浅”结构
int[]newArray=array.clone();
//克隆阵列的“深层”结构
对于(int row=0;row
尝试使用clone()克隆它

或者,使用循环复制所有值

EDIT:Api for clone()说它应该返回对象的副本,但行为可能会有所不同,具体取决于克隆的对象。可以尝试在数组上迭代。由于它是二维数组,因此需要嵌套循环:

for(int i=0; i<old.length; i++)
  for(int j=0; j<old[i].length; j++)
    old[i][j]=copy[i][j];
for(int i=0;i尝试使用clone()克隆它

或者,使用循环复制所有值

EDIT:Api for clone()说它应该返回对象的副本,但行为可能会有所不同,具体取决于克隆的对象。可以尝试在数组上迭代。由于它是二维数组,因此需要嵌套循环:

for(int i=0; i<old.length; i++)
  for(int j=0; j<old[i].length; j++)
    old[i][j]=copy[i][j];

for(int i=0;i实际上,数组没有值,只有指向对象或基本数据类型的指针。如果您想要详细的答案,请阅读我的注释:或此处:

因此,由于数组是指针,如果你克隆一个指针,其中包含指针,会发生什么呢?首先,指针是真实复制的,但这些指针只指向其他未克隆的对象。因此,如果你想克隆,我建议不要使用数组,而是“更难”数据结构:类。另一种可能是永远不要在数组中存储数组…就像我只对容器使用数组一样

但是我不能提供Java多维泛型的详细信息,因为我从来没有处理过它们,不仅仅是因为它们可能不一致,因为它们是数组(它们违反了一些OO原则,使代码看起来很难看)

编辑

我正在运行一些测试,测试clone方法在类中如何处理数组,问题是什么,我们有哪些解决方法

首先是测试数据结构:

public class Foobar implements Cloneable {
    String[] array;

    public Foobar() {
        this.array = new String[10];
    }

    public String getValue(){
        return array[0];
    }

    public String[] getArray(){
        return array;
    }

    public void setArray(String[] array){
        this.array = array;
    }

    @Override
    public Object clone(){
        try{
            Foobar foobar = (Foobar) super.clone();
            foobar.setArray(array);
            return foobar;
        }
        catch(Exception e){
            return null;
        }
    }
}
现在控制器:

String[] array = new String[10];
array[0] = "111";
Foobar foo1 = new Foobar();  
foo1.setArray(array);
Foobar foo2 = foo1; //Alternation: Foobar foo2 = (Foobar) foo1.clone();  
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
array[0] = "999";
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
无论我使用=还是clone(),测试结果都会是这样的:

这不好

那么解决方法是什么呢?我建议在每个数据结构类中都这样做:

public class Foobar implements Serializable {
    //any class variables...it doesn't matter which!

    public Foobar() {
        //do initialisation here...it doesn't matter what you do!
    }

    public Foobar copy(){
        try{
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Foobar foobar = (Foobar) ois.readObject();
            return foobar;
        }
        catch(Exception e){
            return null;
        }
    }
}
因此,只需实现一行代码即可获得完整副本:

Foobar foo2 = foo1.copy(); //nice and easy!!
此解决方案的优点:实现可序列化接口以使类“可复制”通常就足够了。如果没有,您可以通过阅读可序列化Javadoc中编写的内容来解决任何问题

更重要的是:你想让类中的对象成为“可复制对象”并不重要,因此你不需要在这个问题上花费更多的时间。毕竟,上面的代码是迄今为止最简单、最快的深入Java的解决方案,并且只使用RAM!(感谢ByteArrayOutputStream)

享受吧

更新:请注意,如果需要临时堆栈或处理线程,则只需使用对象的副本(通常:如果需要对象彼此完全独立)。否则,您根本不应该进行任何复制!而且,如果您将一些数据写入文件或套接字,您也不需要复制。更重要的是,我建议仅在真正使用复制方法时才实施复制方法:对于数据结构(模型)。因此,请小心使用此强大的方法(否则它可能会减慢你的应用程序速度,或者如果你无缘无故地复制了数百万份,甚至会填满Java虚拟机的存储空间,这将导致堆栈溢出:o)

编辑

我在这个问题上做了更多的工作。因为我突然发现,Java API中没有“primitive”数组的公共clone()方法!!(SUN的“复活节彩蛋”表示字符串[]或int[]等数组;-)

由于我使用实数组作为Foobar(而不是ArrayLists!)的基本数据结构,因此我可以更改(上述类的)clone方法,如
@Override
public Object clone(){
    try{
        Foobar foobar = (Foobar) super.clone();
        String[] arrayClone = array.clone(); //who thought that this is possible?!
        foobar.setArray(arrayClone);
        return foobar;
    }
    catch(Exception e){
        return null;
    }
}
Instance: [Ljava.lang.String;@42e816 with value: 111
Instance: [Ljava.lang.String;@9304b1 with value: 111
Instance: [Ljava.lang.String;@42e816 with value: 999
Instance: [Ljava.lang.String;@9304b1 with value: 111