Java arraylist的副本不断被修改为原始的值

Java arraylist的副本不断被修改为原始的值,java,arraylist,copy,duplicates,clone,Java,Arraylist,Copy,Duplicates,Clone,我正在开发一个用于保存和调用屏幕状态的系统,这是我第一次处理这类事情,所以我不确定最好的方法是什么,但我目前将所有“PreviewMonitor”对象(大约40个)存储在数组列表中。问题是,当我创建一个名为“allPreviewMonitors”的ArrayList副本进行存储时,我最终得到一个ArrayList,其中的元素会随着原始元素的更新而不断变化。这几乎就像我在使用原始ArrayList,而事实上,当我创建allPreviewMonitors副本时,它应该是一个完全不同的ArrayLis

我正在开发一个用于保存和调用屏幕状态的系统,这是我第一次处理这类事情,所以我不确定最好的方法是什么,但我目前将所有“PreviewMonitor”对象(大约40个)存储在数组列表中。问题是,当我创建一个名为“allPreviewMonitors”的ArrayList副本进行存储时,我最终得到一个ArrayList,其中的元素会随着原始元素的更新而不断变化。这几乎就像我在使用原始ArrayList,而事实上,当我创建allPreviewMonitors副本时,它应该是一个完全不同的ArrayList,具有“冻结”版本的元素及其状态。为什么会发生这种行为?如果需要,我可以显示代码,但我不确定这里是否需要。

一个
Arraylist
与所有
集合一样,只包含对对象的引用。
仅复制列表是不够的,在创建列表副本时,还必须克隆()列表中的元素(或创建新元素,或使用复制构造函数)。


这称为“深度复制”,而您当前有一个“浅层复制”。

您需要确保执行“深度复制”-即克隆
PreviewMonitor
对象。默认情况下,您只需执行浅复制并复制对同一对象的引用。

要克隆,您不能只返回当前对象。必须使用与当前对象相同的值创建新对象。换句话说,使用当前对象类的构造函数并创建一个新对象。确保旧对象和新对象之间的属性匹配。返回新对象,并对原始列表中的每个对象重复此操作。

您只是将对象引用复制到ArrayList中。您需要复制对象本身

在Java中,所有对象变量实际上都是引用变量。因此,代码:

Myclass myObject = new Myclass();
Myclass otherObject = myObject;
创建Myclass对象并将对该Myclass对象的引用存储在引用变量
myObject
中。然后创建一个新的引用变量
otherObject
,引用数据(如内存地址)从
myObject
复制到
otherObject
。它们现在引用内存中的同一对象。在这一点上,这条线

myObject.myMethod();
结果与

otherObject.myMethod();
您在ArrayList中得到的是对相同对象的不同引用。 您需要的是以下内容之一:

Myclass otherObject = myObject.clone(); // use the clone function
// OR
Myclass otherObject = new Myclass(myObject); // use a copy constructor
如果使用
clone()
或复制构造函数将对象放入ArrayList,ArrayList将包含对相同副本的引用,而不是对相同副本的引用

正如其他人所指出的,仅仅复制引用被称为“浅拷贝”,而复制引用的对象被称为“深拷贝”

编辑:为了使其工作,您的解决方案不仅必须在您的类上实现,而且必须在您的类中包含的所有类上实现。例如,考虑<代码> MyClass < /代码>,它有一个类型的字段<代码> OtherClass < /代码>:

class MyClass {
  private String foo;
  private OtherClass bar;
  private int x;
  MyClass(String f, OtherClass b, int x) {
    foo = f;
    bar = b;
    this.x = x;
  }

  MyClass(MyClass o) {
    //make sure to call the copy constructor of OtherClass
    this(new String(o.foo), new OtherClass(o.bar), o.x);
  }
  // getters and setters
}
请注意,这需要
OtherClass
也有一个复制构造函数!如果
OtherClass
引用了其他类,那么它们也需要复制构造函数。这是没有办法的

最后,您的列表副本如下所示:

List<MyClass> myNewList = new ArrayList<>(myExistingList.size());
for ( MyClass item : myExistingList) {
  // use the copy constructor of MyClass, which uses the copy constructor of OtherClass, etc, etc.
  myNewList.add(new MyClass(item))
}
List myNewList=newarraylist(myExistingList.size());
对于(MyClass项:myExistingList){
//使用MyClass的复制构造函数,它使用OtherClass的复制构造函数,等等。
添加(新的MyClass(项目))
}

如何准确地“克隆”PreviewMonitor对象。我认为这可能是个问题,所以我创建了一些东西来测试它,并在PreviewMonitor对象中创建了一个我认为应该创建的“克隆”方法,但我不确定我是否做对了。public PreviewMonitor clone(){return this;}我假设
PreviewMonitor
是您自己的对象之一。克隆过程取决于对象。您通常会调用clone()方法。更多信息请访问。我如何“克隆”PreviewMonitor对象。我认为这可能是个问题,所以我创建了一些东西来测试它,并在PreviewMonitor对象中创建了一个我认为应该创建的“克隆”方法,但我不确定我是否做对了。public PreviewMonitor clone(){return this;}我已经尝试了(PreviewMonitor sourcePreviewMonitor:previewMonitors){this.previewMonitors.add(新的PreviewMonitor(sourcePreviewMonitor.getPos(),sourcePreviewMonitor.getJButton().getX(),sourcePreviewMonitor.getJButton().getY(),sourcePreviewMonitor.getJButton().getWidth()),sourcePreviewMonitor.getJButton().getHeight(),sourcePreviewMonitor.getColumn(),sourcePreviewMonitor.getRow(),sourcePreviewMonitor.getRight());}--并为PreviewMonitor对象创建一个新的构造函数,使其接受一个参数、另一个PreviewMonitor并将其传入。但是,我尝试使用复制构造函数,这导致了相同的输出。可能是因为PreviewMonitor(我的对象)包含一个JButton对象,这是我使用PreviewMonitor.getJButton()从中提取对象的原因吗?我也尝试过上述方法,但当我修改克隆对象时,它也会反映在原始对象中,不知道出了什么问题。要清楚,您需要对整个对象进行深度复制,包括其中的所有对象。而且,您必须在类的代码中实际实现这一点。您必须提供一个复制构造函数(或克隆方法)来实际复制类中的每个项。