一位同事最近问我如何深度克隆Map,我意识到我可能从未使用过克隆()方法 - 这让我很担心。
您找到克隆对象的最常见方案是什么?
答案 0 :(得分:15)
我假设您在Java中引用Object.clone()
。如果是,请注意Object.clone()
有一些重大问题,并且在大多数情况下不鼓励使用它。请参阅Joshua Bloch的"Effective Java"中的第11项,以获得完整的答案。我相信你可以安全地在原始类型数组上使用Object.clone()
,但除此之外,你需要明智地正确使用和覆盖克隆。您最好定义一个复制构造函数或静态工厂方法,根据您的语义显式克隆该对象。
答案 1 :(得分:5)
最常见的情况是,当我必须将一个可变对象返回给调用者时,我担心调用者可能会捣乱,通常是以线程不友好的方式。列表和日期是我最常做的。如果调用者可能想要迭代List并且我有线程可能更新它,那么返回它的克隆或副本会更安全。
实际上,这会带来一些我需要开辟的另一个问题:复制构造函数还是克隆?当我做C ++时,我们总是做一个复制构造函数并用它实现克隆,但是如果你使用复制构造函数实现克隆,FindBugs不喜欢它。
答案 2 :(得分:3)
当我需要复制某些内容来修改副本而不影响原始副本时,当然在这种情况下深度克隆(仅限)就足够了。我必须在一个系统上执行此操作,我将克隆一个域类实例,应用用户的更改,然后执行两者的比较,以便用户验证其更改。
答案 3 :(得分:2)
Object.clone()方法没有指定子类的副本是深拷贝还是浅拷贝,它完全依赖于特定的类。 Object.clone()方法本身执行浅拷贝(复制Object类的内部状态),但是子类必须覆盖它,调用super.clone(),并根据需要复制它们的内部状态(浅或深)。 p>
它确实指定了一些您可能遵循或不遵循的约定。对于(a.getClass()== a.clone()。getClass())返回true,应调用super.clone()而不是简单的'new Subclass()',因为super.clone()可能会正确实例化此对象的类(即使在子类中),并复制所有内部状态,包括私有字段,这些字段无法使用复制构造函数由子类复制,因为可见性规则。或者你将被迫暴露一个不应该暴露的构造函数,以便更好地封装。
示例:
//simple clone
class A implements Cloneable {
private int value;
public A clone() {
try {
A copy = (A) super.clone();
copy.value = this.value;
return copy;
} catch (CloneNotSupportedException ex) {}
}
}
//clone with deep and shallow copying
class B extends A {
Calendar date;
Date date;
public B clone() {
B copy = (B) super.clone();
copy.date = (Calendar) this.date.clone(); // clones the object
copy.date = this.date; // copies the reference
return copy;
}
}
当依赖对象是可变的(如日历)时,通常使用深层复制,并且副本必须完全独立于原始文件。
当依赖对象是不可变的(如Date)时,共享同一个实例通常不是问题,浅拷贝可能就足够了。
使用Object.clone()时,您必须遵循一些规则,但它们很简单,易于理解。可能最困难的部分是正确定义应该复制到对象图中的深度。这是一个逻辑问题,而不是语言问题。
答案 4 :(得分:0)
我在Spring webflow应用程序中使用了Object.clone()来检查用户在表单上编辑/输入数据以进行审计时发生的变化。
在流程的开头,我调用了在spring webflow中使用的表单支持对象上实现的clone方法,并将clone的实例保存到用户会话中。一旦用户完成了html表单上的数据编辑并按下了保存按钮,我将绑定到后备对象的新值与克隆值进行比较,以确定用户已更改的数据。
这很好用,并且很容易实现,我在Java中克隆时没有遇到任何问题。