5

私はJavaプログラミングの家庭教師です。私の生徒は現在、抽象クラスにclone()equals()hashCode()を実装することを(私ではなく、不明確な割り当てによって)強制されています。

抽象クラスにclone()、equals()、またはhashCode()を実装することは意味がありますか?これが理にかなっている例を挙げていただけますか?

抽象クラスaのサブクラスx、y、zがある場合、それは理にかなっていると想像できます。これらのサブクラスは、メソッドの実装のみが異なる可能性があるため、これら3つのメソッドを3回実装する必要はありません。しかし、これが当てはまる状況は想像できません。

4

6 に答える 6

4

私は実装しませんclone()

ただし、、を実装equals()し、すべてのサブクラスにデフォルトの動作を提供することは理にかなっています。新しいクラスのメンバーを追加したり、必要に応じて補足したりしない場合、子供はそれを使用することを選択できます。hashCode()toString()

于 2013-01-07T17:29:40.483 に答える
1

の主な問題clone()は、それを実装する方法が2つあり、派生クラスでの適切な実装は、その親クラスが何をするかに依存することです。

親クラスとそのすべての祖先super.clone()が呼び出しに達するまで呼び出すobject.clone()場合、派生クラスが行う適切なことは、呼び出しsuper.cloneてから、ターゲットオブジェクトの可変状態をカプセル化する「追加された」メンバーを置き換えることですが、それらのIDはカプセル化しません。同じ状態をカプセル化する新しいオブジェクト。派生クラスに、可変オブジェクトの状態をカプセル化する追加メンバーが含まれていない場合、派生クラスは何もする必要はありませんがclone、親の実装を使用するだけで済みます。

クラスを実装するもう1つの方法はclone()、独自の型の引数を受け入れるコンストラクターをクラスに含め、同様に行う親コンストラクターにチェーンして、「新しい」すべての適切なプロパティをその型にコピーすることです。新しいインスタンスに渡されたインスタンス。このアプローチの利点は、基本クラスがcloneこのように実装されている場合でも機能することです。ただし、このアプローチには2つの欠点があります。

  1. 追加されたメンバーが可変状態をカプセル化するかどうかに関係なく、すべての派生型はclone()を再実装する必要があります
  2. すべての派生型は、super.clone()を呼び出すのではなく、このアプローチを使用してclone()を実装する必要があります。
clone()型が呼び出しによって 実装されているsuper.clone()が、そうでない祖先が存在する場合、結果のオブジェクトは、派生型ではなく親型になり、clone()動作するはずの方法ではないことに注意してください。

于 2013-01-07T19:50:21.703 に答える
1

1)clone()メソッドは、ある種のオブジェクトのディープ コピーを実装する必要があり、同時にこのオブジェクトへの参照だけを使用することはできず、それらの新しいインスタンスが必要な場合に非常に便利です。したがって、このメソッドをオーバーライドすることには意味があります。

2)equals()hashCodeは 2 つの重要なメソッドであり、HashSet/HashMapこれらのメソッドの実装に依存する の特別な動作が必要な場合にオーバーライドする必要があります。したがって、それらをオーバーライドすることにも意味があります。

于 2013-01-07T17:42:31.397 に答える
1

あなたの質問とあなたが尋ねた考えを誤解しましたtoString- とにかく同じ理由が適用されます

たとえば、基本的にコレクションを反復処理し、ユーザーフレンドリーな方法で出力するAbstractCollection実装。toString()

直接サブクラス:

AbstractList, AbstractQueue, AbstractSet, ArrayDeque, ConcurrentLinkedDeque

したがって、すべてのセット、リスト、およびキューがそのtoStringメソッドを共有します。各サブクラスは、必要に応じて自由に再実装できます。

別の例として、equals1 つ下のレベル (AbstracList/Set など) に実装されています。

一方、cloneは最終的な実装 (ArrayList など) に実装されていますが、抽象クラスには実装されていません。

結論: 理にかなっている場合もあれば、そうでない場合もあり、すべての状況に適用される義務ではないはずです。

于 2013-01-07T17:27:51.347 に答える
0

メソッドclone()、equals()、hasCode()は、抽象クラスに存在しないフィールドを必要とするため、通常、その抽象クラスを実装するクラスに実装する必要があります。

ただし、equals()、hascode()、およびおそらくclone()が抽象クラスに実装するのが理にかなっている状況がいくつかあります。(たとえば、equals()は、Collectionsなどの抽象コンテナークラスで意味があります)

hashCode()とclone()については、それが理にかなっているのかどうか疑問があります。

于 2013-01-07T17:31:51.887 に答える
0

それは理にかなっていますか?

  • 抽象クラスが、特にサブクラスにアクセスできない状態に関して、標準の動作を変更したい場合、オーバーライドclone()することは理にかなっています。clone()
  • 抽象スーパークラスが同等の動作に関する契約を強制している場合は、オーバーライドequals()hashCode()て意味があります。このコントラクトは、それ自体で指定することも、スーパークラスまたはそれが実装するインターフェースによって指定することもできます。

これらをオーバーライドするために抽象的なスーパークラスを設計したいと思うことはありますか?

  • 回答の他の場所で述べたように、clone()メカニズム自体が適切であることはめったにありません。1 つの適切な実装は、明示的に a をスローしCloneNotSupportedExceptionてそれを作成することfinalであり、この方法でサブクラスが を実装するのを防ぎますCloneable
  • Forequals()hashCode()sensible ケースも適切なケースです。抽象スーパークラスがそれ自体で等価コントラクトの仕様を満たすことができる場合は、そうする必要があります。また、LSP 違反を防ぐために、 equals()andhashCode()メソッドを作成する必要があります。finalJosh Bloch の言葉を引用します。

イコール コントラクトを保持しながら、インスタンス化可能なクラスを拡張して値コンポーネントを追加する方法はありません -有効な Java 2nd ed.

于 2013-01-07T19:09:24.230 に答える