2

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

4

4 回答 4

5

一个Arraylistlike all Collections,只包含对对象的引用。仅复制 List 是不够的,您还必须在创建 List 副本时 clone() 列表中的元素(或创建新元素,或使用复制构造函数)。

这称为制作“深拷贝”,而您目前有一个“浅拷贝”。

于 2013-02-07T02:19:40.210 回答
3

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

于 2013-02-07T02:19:46.747 回答
3

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

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

Myclass myObject = new Myclass();
Myclass otherObject = myObject;

创建一个 Myclass 对象并将对该 Myclass 对象的引用存储在引用变量myObject中。然后它会创建一个新的引用变量otherObject,并将引用数据(例如内存地址)从 复制myObjectotherObject。这些现在指的是内存中的同一个对象。此时,线

myObject.myMethod();

具有相同的结果

otherObject.myMethod();

您在 ArrayList 中得到的是对相同对象的不同引用。你想要的是以下之一:

Myclass otherObject = myObject.clone(); // use the clone function
// OR
Myclass otherObject = new Myclass(myObject); // use a copy constructor

如果使用复制构造函数将对象放入 ArrayList 中clone(),则 ArrayList 将包含对相同副本的引用,而不是对相同副本的引用。

正如其他人指出的那样,仅制作引用的副本称为“浅拷贝”,而制作引用的对象的副本称为“深拷贝”。

编辑:为了使它起作用,您的解决方案不仅要在您的班级上实施,而且要在您班级中包含的所有班级上实施。例如,考虑MyClasswhich 具有 type 的字段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))
}
于 2013-02-08T03:13:13.560 回答
1

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

于 2013-02-07T03:31:30.230 回答