听起来这里至少有两个问题在起作用:
听起来您对通常如何实现 clone() 感到困惑。
听起来您认为克隆是一个好主意(与使用复制构造函数、工厂或它们的等效项相比)。
下面是一个克隆方法的实现示例:
@Override
public Object clone() throws CloneNotSupportedException {
//get initial bit-by-bit copy, which handles all immutable fields
Fruit result = (Fruit)super.clone();
//mutable fields need to be made independent of this object, for reasons
//similar to those for defensive copies - to prevent unwanted access to
//this object's internal state
result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );
return result;
}
请注意, 的结果super.clone()
会立即转换为Fruit
. 这允许继承方法随后修改 Fruit 特定的成员数据(fBestBeforeDate
在本例中)。
因此,对子clone()
方法的调用虽然会调用父方法的克隆,但也会将其自己的特定修改添加到新制作的副本中。在这种情况下,结果将是 a Fruit
,而不是Object
。
现在,更重要的是,克隆是个坏主意。复制构造函数和工厂提供了更直观且易于维护的替代方案。尝试阅读我附加到示例的Java 实践链接上的标题:它总结了一些问题。Josh Bloch 也有更长的讨论:绝对应该避免克隆。以下是关于他为什么认为克隆是一个问题的精彩摘要段落:
Object 的 clone 方法非常棘手。它基于现场副本,并且是“语言外的”。它创建一个对象而不调用构造函数。不能保证它保留了构造函数建立的不变量。多年来,无论在 Sun 内部还是外部,都出现了很多错误,这是因为如果您只是在链上反复调用 super.clone 直到您克隆了一个对象,您就会得到该对象的浅表副本。克隆通常与被克隆的对象共享状态。如果该状态是可变的,则您没有两个独立的对象。如果你修改一个,其他的也会改变。突然之间,你得到随机行为。