2

我有一个ArrayList包含对象。(这个对象是类,每个对象都包含大量的信息,这些对象恰恰代表了大型发电机,所以不能一个个地复制属性)。

例子:

ArrayList arr = {ob1, ob2, ob3, ob4, ob5}

所以我尝试做的是将对象(ob1)克隆到位置 5。

arr.set(4, arr.get(0));

但不知何故,这样做,ob5 不是 ob ob1 的副本,它是 ob1,所以如果我更改 ob5,ob1 也会更改。

这是 ArrayLists 固有的吗?如果我改用列表有什么区别吗?

4

9 回答 9

2

ArrayList 保存引用是的。但是您可以克隆它(注意!但这将是浅拷贝 - 对于内部对象,它也不会克隆https://stackoverflow.com/a/13434779/1111527

private class JustToCheck implements Cloneable {

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

然后像这样使用

JustToCheck ob1 = new JustToCheck();
JustToCheck ob2 = ob1;

List<JustToCheck> arr = new ArrayList<JustToCheck>();
arr.add(ob1);
arr.add(ob2);

System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());

try {
    arr.set(1, (JustToCheck) ob1.clone());
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

System.out.println(arr.get(0).toString() + ": " + arr.get(1).toString());

输出是

example$JustToCheck@1c39a2d: example$JustToCheck@1c39a2d
example$JustToCheck@1c39a2d: example$JustToCheck@bf2d5e


PS - 我已经检查了答案中的问题https://stackoverflow.com/a/13434813/1111527

有不可变类的东西

Java6

String a = new String("a");
String b = a;
b += "b"; 
System.out.println("a = " + a); // a = a
System.out.println("b = " + b); // b = ab
于 2012-11-30T14:23:45.590 回答
1

这是因为您正在执行卷影复制而不是深层复制。

浅拷贝:如果执行浅拷贝,Obj-1那么它会被复制,但它包含的对象不会。包含的对象Obj-1Obj-2克隆的 Obj-2 更改的影响。当类实现 java.lang.Cloneable 接口时,Java 默认支持对象的浅层克隆。

深拷贝:如果按所示执行深拷贝,obj-1则不仅复制了obj-1,还复制了其中包含的对象。序列化可用于实现深度克隆。通过序列化进行的深度克隆开发起来更快,更容易维护,但会带来性能开销。资源

深拷贝的一个例子:

class Student implements Cloneable {
  //Contained object
  private Subject subj;
  private String name;

  public Subject getSubj() {..}
  public String getName() {..}

  public Object clone() {
    //Deep copy
    Student s = new Student(name, subj.getName());
    return s;
  }
}
于 2012-11-17T21:05:23.090 回答
0

shallow copying创建同一类的新实例并将所有字段复制到新实例并返回它。Object 类提供了一个克隆方法并提供了对浅拷贝的支持。

于 2012-11-17T21:31:24.027 回答
0

在 Java 中的任何地方都是如此。 除非您明确这样做,否则不会复制任何内容。(确实,有些对象是故意无法复制的。)

于 2012-11-17T21:06:51.603 回答
0

您需要复制您的ElectricGenerator. 最常见的选项是引入复制构造函数或实现克隆方法。然而,这两种解决方案都需要复制所有这些属性。

一旦你有了它,你就可以做到

//copy constructor
arr.add( new ElectricGenerator( arr.get( 0 ) ) );
//clone
arr.add( arr.get( 0 ).clone() );

另一种方法是序列化/反序列化对象

于 2012-11-17T21:08:06.610 回答
0

这不符合 ArrayList,这是一个 java 特性。没有创建新对象,只传递了一个引用。ArrayList 因此存储了两个引用。您必须使用对象的 .clone() 方法。

arr.set(4, arr.get(0).clone());

这将创建对象的新副本,即使此副本很浅。如果需要,您必须覆盖克隆方法以使其成为深层副本。

于 2012-11-17T21:08:39.323 回答
0

不,这是因为在 Java 中您创建了对对象的引用,所以即使您不使用 ArrayList 并执行以下操作:

String a = new String("a");
String b = a;

b += "b";

a 和 b 都等于“ab”。

(这个例外是基本类型,如 int (但不是 Integer 的实例,有不同的东西))。

因此,您的问题的答案在这里: 如何按值复制对象,而不是通过引用 ,在这里: http ://www.itcsolutions.eu/2010/12/29/tutorial-java-6-4-2-how -to-copy-values-of-an-array-into-another-array/

于 2012-11-17T21:09:48.023 回答
0

该列表仅包含指向对象的指针..

如果您将 ob1 移动到 ob5 会发生什么情况,您告诉列表将指针放在 ob1 的指针 ob5 所在的位置,因此丢失指向 ob5 的指针并复制指向 ob1 的指针...

您将需要创建一个包含重复值的其他对象,然后将此对象分配给位置 4

于 2012-11-17T21:10:41.530 回答
0

对象变量不同于原始数据类型。

int x = 2;
int y = x;

x 和 y 指的是不同的内存位置。

MyClass x = new MyClass();
MyClass y = x;

x 和 y 引用相同的内存位置,但该位置有两个引用。对其中一个所做的任何更改都会改变另一个。解决此问题的方法是实施Cloneable和使用该.clone()方法。

于 2012-11-17T21:11:58.300 回答