小编典典

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

java

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


阅读 259

收藏
2020-11-26

共1个答案

小编典典

您仅将对象引用复制到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

如果使用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))
}
2020-11-26