ここでは、少なくとも 2 つの問題が発生しているようです。
clone() が通常どのように実装されるかについて混乱しているようです。
クローン作成は良いアイデアだと考えているようです (コピー コンストラクター、ファクトリ、またはそれらに相当するものを使用するのではなく)。
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()
メソッドへの呼び出しは、親のクローンを呼び出しますが、新しく作成されたコピーに独自の特定の変更も追加します。この場合、出てくるのはFruit
ではなくObject
です。
さらに重要なことに、クローンは悪い考えです。コピー コンストラクターとファクトリは、はるかに直感的で保守が容易な代替手段を提供します。例に添付したJava Practicesリンクのヘッダーを読んでみてください。いくつかの問題が要約されています。Josh Bloch も、より長い議論を行っています: クローンは絶対に避けるべきです。以下は、クローンが問題であると彼が考えている理由についての優れた要約の段落です。
オブジェクトの clone メソッドは非常にトリッキーです。これはフィールド コピーに基づいており、「言語外」です。コンストラクターを呼び出さずにオブジェクトを作成します。コンストラクターによって確立された不変条件が保持されるという保証はありません。Sun の内外で長年にわたって多くのバグがありました。これは、オブジェクトのクローンを作成するまでチェーンの中で super.clone を繰り返し呼び出すと、オブジェクトの浅いコピーが作成されるという事実に起因しています。クローンは通常、クローンされるオブジェクトと状態を共有します。その状態が変更可能な場合、2 つの独立したオブジェクトはありません。一方を変更すると、他方も変更されます。そして突然、ランダムな動作になります。