你用了什么Object.clone()?

一位同事最近问我如何深度克隆Map,我意识到我可能从未使用过克隆()方法 – 这让我很担心。

您找到克隆对象的最常见方案是什么?

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

最常见的情况是,当我必须将一个可变对象返回给调用者时,我担心调用者可能会捣乱,通常是以线程不友好的方式。 列表和日期是我最常做的。 如果调用者可能想要迭代List并且我有线程可能更新它,那么返回它的克隆或副本会更安全。

实际上,这会带来一些我需要开辟的另一个问题:复制构造函数还是克隆? 当我做C ++时,我们总是做一个复制构造函数并用它实现克隆,但如果你使用复制构造函数实现你的克隆,FindBugs不喜欢它。

当我需要复制某些内容来修改副本而不影响原始副本时,当然在这种情况下深度克隆(仅限)就足够了。 我必须在一个系统上执行此操作,在该系统中,我将克隆域类实例,应用用户的更改,然后执行两者的比较,以便用户validation其更改。

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; } } 

当依赖对象是可变的(如Calendar)时,通常使用深层复制,并且副本必须完全独立于原始对象。

当依赖对象是不可变的(如Date)时,共享同一个实例通常不是问题,浅拷贝可能就足够了。

使用Object.clone()时,必须遵循一些规则,但它们很简单,易于理解。 可能最困难的部分是正确定义您应该将深度复制到对象图中的深度。 这是一个逻辑问题,而不是语言问题。

我在Spring webflow应用程序中使用了Object.clone()来检查用户在表单上编辑/输入数据以进行审计时发生的变化。

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

这很好用,并且非常容易实现,我在Java中克隆时没有遇到任何问题。