听起来这里至少有两个问题在起作用:
听起来你对 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
fBestBeforeDate
因此,对子方法的调用虽然会调用父级的克隆,但也会将其自己的特定修改添加到新创建的副本中。在这种情况下,出来的将是 一个 ,而不是一个 .clone()
Fruit
Object
现在,更重要的是,克隆是一个坏主意。复制构造函数和工厂提供了更直观且易于维护的替代方法。尝试阅读我附加到示例的 Java 实践链接上的标头:它总结了一些问题。乔希·布洛赫(Josh Bloch)也有一个更长的讨论:克隆绝对应该避免。这里有一个很好的总结段落,说明为什么他认为克隆是一个问题:
对象的克隆方法非常棘手。它基于现场副本,并且是“语言外的”。它创建一个对象而不调用构造函数。不能保证它保留构造函数建立的不变量。多年来,无论是在 Sun 内部还是外部,都有很多 bug,这是因为如果你只是在链上反复调用 super.clone,直到你克隆了一个对象,你就有了一个对象的浅副本。克隆通常与要克隆的对象共享状态。如果该状态是可变的,则没有两个独立的对象。如果修改一个,另一个也会更改。突然之间,你得到了随机的行为。