如何正确覆盖克隆方法?

问题

我需要在我的一个没有超类的对象中实现深度克隆。

超类(isObject)处理checkedCloneNotSupportedExceptionthrown的最佳方法是什么?

一位同事建议我按以下方式处理:

@Override
public MyObject clone()
{
    MyObject foo;
    try
    {
        foo = (MyObject) super.clone();
    }
    catch (CloneNotSupportedException e)
    {
        throw new Error();
    }

    // Deep clone member fields here

    return foo;
}

这对我来说似乎是一个很好的解决方案,但我想把它扔到StackOverflow社区,看看我是否还有其他任何见解。谢谢!


#1 热门回答(115 赞)

你绝对要使用clone吗?大多数人都认为Java的clone已被破坏。
Josh Bloch on Design - Copy Constructor versus Cloning>如果你已经阅读了我的书中有关克隆的项目,特别是如果你在各行之间阅读,你将会知道我认为克隆已经深受打击。 [...] Cloneable被打破是一种耻辱,但它确实发生了。

你可以在他的书"有效Java第2版,第11项:Overrideclone"中阅读有关该主题的更多讨论。他建议改为使用复制构造函数或复制工厂。

他接着写了一些页面,如果你觉得必须,你应该如何实施clone。但他以此结束了:

所有这些复杂性真的有必要吗?很少。如果扩展一个实现Cloneable的类,那么除了实现一个行为良好的克隆方法之外别无选择。否则,最好提供替代的对象复制方法,或者根本不提供该功能。

重点是他,而不是我的。

既然你明确表示你别无选择,只能实施clone,那么在这种情况下你可以做的就是:确保MyObject extends java.lang.Object implements java.lang.Cloneable。如果是这种情况,那么你可以保证你将2424229907从不catch aCloneNotSupportedException。抛出AssertionError,有些人认为这似乎是合理的,但你也可以添加一个注释来解释为什么在这个特殊情况下中永远不会输入catch块为**。

或者,正如其他人也建议的那样,你可以实现clone而不需要调用super.clone


#2 热门回答(52 赞)

有时,实现复制构造函数更简单:

public MyObject (MyObject toClone) {
}

它可以省去处理CloneNotSupportedException的麻烦,适用于final字段,你不必担心要返回的类型。


#3 热门回答(11 赞)

代码的工作方式非常接近于编写它的"规范"方式。不过,我会扔掉一个AssertionError。它表示永远不应该到达那条线。

catch (CloneNotSupportedException e) {
    throw new AssertionError(e);
}