2008-11-06 75 views
14

一位同事最近问我如何深度克隆一个Map,并且我意识到我可能从来没有使用clone()方法 - 这让我很担心。你用Object.clone()做了什么?

在您需要克隆对象的地方,您发现了哪些最常见的场景?

回答

15

我假定您指的是Java中的Object.clone()。如果是,请注意Object.clone()存在一些主要问题,并且在大多数情况下不鼓励使用它。请参阅Joshua Bloch的"Effective Java"中的项目11获取完整答案。我相信您可以在原始类型数组上安全使用Object.clone(),但除此之外,您需要明智地正确使用和覆盖克隆。你最好定义一个拷贝构造函数或一个静态工厂方法,根据你的语义显式地克隆这个对象。

5

最常见的情况是,当我不得不将一个可变对象返回给调用者时,我担心调用者可能会使用这种调用方法,而且往往以线程不友好的方式。列表和日期是我为此做的最多的。如果调用者可能想遍历一个List,并且有线程可能更新它,则返回它的一个克隆或副本会更安全。

其实,这提出了一些我将不得不打开另一个问题:复制构造函数或克隆?当我做C++的时候,我们总是做了一个拷贝构造函数并实现了它的克隆,但是如果你使用拷贝构造函数来实现你的克隆,FindBugs不会喜欢它。

+0

如果您使用复制构造函数来实现clone(),而不是调用super.clone(),那么当某人对您的类进行子类分类并调用clone时,它们将获得超类类型的对象,而不是子类类型。 – 2008-11-06 23:42:55

+0

@丹,是的,这几乎是FindBugs所说的。刚刚阅读了一些从StackOverflow的答案链接到关于C++的问题后,我现在可以明白,在C++中这样做并不是很好。 – 2008-11-07 03:22:02

3

当我需要复制某些内容以修改重复内容而不影响原始内容时,当然在这种情况下,只需要进行深度克隆即可。我必须在一个系统上执行此操作,在该系统中,我将克隆域类实例,应用用户的更改,然后对两者进行比较以供用户验证其更改。

2

Object.clone()方法不指定子类的副本是深层还是浅层副本,它完全依赖于特定的类。 Object.clone()方法本身做一个浅拷贝(拷贝Object类的内部状态),但是子类必须覆盖它,调用super.clone(),并根据需要拷贝它们的内部状态(浅或深)。

它确实规定了一些约定,你可能不遵守。对于(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()时,您必须遵循一些规则,但它们很简单,可以理解。可能最困难的部分是正确定义你应该复制到对象图表中的深度。一个逻辑问题,而不是语言问题,即。

0

我已经使用了Object。克隆()在Spring Webflow应用程序中检查用户在表单上编辑/输入数据以进行审计时发生了什么变化。

在流程开始时,我调用在Spring Webflow中使用的窗体支持对象上实现的克隆方法,并将克隆的实例保存到用户会话中。一旦用户在html表单上完成编辑数据并按下保存按钮,我将绑定到后备对象的新值与克隆值进行比较,以确定用户已更改的数据。

这工作得很好,很容易实现,我没有真正遇到任何与Java克隆有关的问题。