可能重复:
Java: how to clone ArrayList but also clone its items?
我有一个示例程序,如下所示:
ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();
//add some items into it here
ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();
copiedInvoice.addAll(orginalInvoice);
我以为我可以修改copiedInvoice
内的项目,但不会影响originalInoice
中的这些项目。但是我错了。
如何对ArrayList
?
由于
答案 0 :(得分:39)
是的,这是正确的 - 你需要实现clone()
(或其他合适的机制来复制你的对象,因为clone()
被许多程序员视为“破坏”。您的clone()
方法应该对对象中的所有可变字段执行深层复制。这样,对克隆对象的修改不会影响原始对象。
在您的示例代码中,您创建了第二个ArrayList
并使用对相同对象的引用填充它,这就是为什么{{1}可以看到对象的更改的原因}秒。使用克隆方法,您的代码将如下所示:
List
编辑:为了澄清,上述代码正在执行原始List<Foo> originalList = ...;
// Create new List with same capacity as original (for efficiency).
List<Foo> copy = new ArrayList<Foo>(originalList.size());
for (Foo foo: originalList) {
copy.add((Foo)foo.clone());
}
的深层复制,其中新List
包含对副本的引用原始对象。这与调用List
形成对比,ArrayList.clone()
执行shallow copy
的{{1}}。在此上下文中,浅表副本会创建一个新的List
实例,但包含对原始对象的引用。
答案 1 :(得分:17)
如果要将可变对象存储到ArrayList中,则需要在复制ArrayList时复制每个对象。否则,新的ArrayList仍将保留原始引用。
但是如果你要存储不可变对象,可以使用它:
ArrayList copiedInvoice = new ArrayList(originalInvoice);
答案 2 :(得分:2)
我以为我可以修改copiedInvoice中的项目,它不会影响originalInoice中的这些主题。
这是因为复制的是引用变量而不是它自己的对象。
因此,您最终得到两个指向同一对象的“引用”。
如果您需要复制整个对象,则可能需要克隆它。
但如果您没有克隆对象内部属性(如果它们碰巧是其他对象),则可能会遇到问题。
例如,以下类定义不会给您带来任何问题。
public class Something {
private int x;
private int y;
private String stringObject;
}
如果你创建了它的副本,你将复制其属性的当前值,就是这样。
但是如果你的类里面有另一个对象,你也可以考虑克隆它。
class OtherSomething {
Something something;
private int x;
}
如果您执行以下操作:
Something shared = new Something();
OtherSomething one = new OtherSomething();
OtherSomething two = new OtherSomething();
one.something = shared;
two.something = shared;
在这种情况下,一个和两个具有相同的共享“某物”的相同参考变量,而改变一个中的值会影响另一个。
这就是使用不可变对象更简单/更好/更容易的原因。
如果需要更改不可变对象的值,只需创建一个具有正确值的新值即可。
答案 3 :(得分:-1)
看看ByteArrayOutputStream和ByteArrayInputStream。如果所有类都实现了Serializable,那么您可以使用上面提到的类进行复制。