92

オーバーライドしながら言っていろいろな所で読みましたequalsJavaのメソッド、オーバーライドする必要がありますhashCodeメソッドも、そうでなければそれは "契約違反"です。

しかし、これまでのところ、equalsメソッドのみをオーバーライドし、hashCodeメソッドをオーバーライドしないのであれば、問題は発生していません。

契約とは何ですか?契約に違反しても、なぜ問題にならないのですか。 hashCodeメソッドをオーバーライドしていないと、どのような場合に問題が発生しますか?


  • この「契約」に関すること何もない実施するそれ。あなたがそれを破っても、何もすぐには壊れません。しかし他のコードあなたが契約のあなたの部分に従わないならば、あなたの物を扱うそれは「壊れる」のは自由です。そのようなオブジェクトを使用しようとすると、まさにそのことが起こります。HashMap。 - Joachim Sauer
  • javaworld.com/article/2074996/… - Sasikumar Murugesan

7 답변


129

あなたが持つ問題は、要素の統一性が両方に従って計算されるコレクションにあります.equals()そして.hashCode()例えば、HashMap

その名前が暗示するように、それはハッシュテーブルに頼ります、そして、ハッシュバケツはオブジェクトの機能です.hashCode()

2つのオブジェクトがある場合.equals()、しかし、異なるハッシュコードを持っている、あなたは失う!

ここで重要な契約の部分は次のとおりです。あるオブジェクト.equals()同じ持っている必要があります.hashCode()

これはすべてに文書化されていますのJavadocObject。そしてジョシュアブロッホあなたはそれをしなければならないと言う効果的なJava。十分に言った。


  • ショート&ナフは言った。 +1 - ManishS
  • @ fge 1つ混乱していますが、HashMapの場合にhashCodeメソッドをオーバーライドするときに、equalsメソッドをオーバーライドする必要があるのはなぜですか? 。いずれの場合も、オブジェクトのハッシュコードが等しい場合、ハッシュマップは値を置き換えます。 - Vikas Verma
  • @VikasVermaいいえ、違います。最初に、キーのハッシュコードが計算され、次に正しいバケットが等しいかどうかが問い合わせられます。 .equals()をオーバーライドしないと、同じハッシュコードを持つ2つのオブジェクトが等しくないという状況になる可能性があります。これは、.equals()のデフォルトの実装が参照等価であるためです。==) - fge

14

ドキュメントによると、hashCodeのデフォルト実装はオブジェクトごとに異なる整数を返します。

合理的に実用的である限り、クラスObjectによって定義されたhashCodeメソッドは、   異なるオブジェクトに対して異なる整数を返します。 (これは典型的には   オブジェクトの内部アドレスを整数に変換しますが、この実装は

JavaTMプログラミング言語ではこの手法は必要ありません。)

ただし、同じ意味を持つ異なるオブジェクトに対してハッシュコードを同じにしたい場合があります。例えば

Student s1 = new Student("John", 18);
Student s2 = new Student("John", 18);
s1.hashCode() != s2.hashCode(); // With the default implementation of hashCode

HashTable、HashSetなどのコレクションフレームワークでハッシュデータ構造を使用すると、この種の問題が発生します。特にHashSetのようなコレクションでは、要素が重複してSet規約に違反することになります。


10

はい、上書きされるべきです。上書きする必要があると思う場合equals()その後、あなたが上書きする必要がありますhashCode()およびその逆。の一般契約ハッシュコード()です:

  1. Javaアプリケーションの実行中に同じオブジェクトに対して複数回呼び出される場合は、オブジェクトの等価比較で使用される情報が変更されていない限り、hashCodeメソッドは常に同じ整数を返す必要があります。この整数は、アプリケーションの実行ごとに同じアプリケーションの実行ごとに一貫性を保つ必要はありません。

  2. 2つのオブジェクトがequals(Object)メソッドに従って等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数結果が得られます。

  3. 2つのオブジェクトがequals(java.lang.Object)メソッドに従って等しくない場合、2つの各オブジェクトでhashCodeメソッドを呼び出すと、異なる整数結果が得られる必要はありません。ただし、プログラマは、等しくないオブジェクトに対して個別の整数結果を生成すると、ハッシュテーブルのパフォーマンスが向上する可能性があることに注意する必要があります。


5

見るのJavaDocjava.lang.Object

hashCode()それは言います:

2つのオブジェクトがequals(Object)方法、   それからhashCode2つのオブジェクトそれぞれのメソッドしなければならない   同じ整数結果を生成する

(私が強調する)

上書きするだけの場合equals()ではなくhashCode()あなたのクラスはこの契約に違反しています。

これは、のJavaDocでも言われています。equals()方法:

通常は上書きする必要があります。hashCode方法   一般を維持するために、このメソッドがオーバーライドされるたびに   の契約hashCodeメソッド。等しいオブジェクトは必ず   ハッシュコードが等しい


4

契約は、obj1.equals(obj2)それからobj1.hashCode() == obj2.hashCode()マップは主にエントリキーを比較するためにhashCodeメソッドを使用しているため、これは主にパフォーマンス上の理由からです。


  • obj1!= obj2then obj1.hasCode()!= obj2.hashCode()< - trueではありません。異なるハッシュコードがあるかもしれませんが、これはではない要件 - fge
  • @ fgeあなたが正しい、ハッシュコードが衝突する可能性がある、編集する - gma

3

契約は、2つのオブジェクトが等しい場合は同じハッシュコードを持つべきであり、2つのオブジェクトが等しくない場合は同じハッシュコードを持つ場合も持たない場合もあります。

あなたのオブジェクトをHashMap(joachim-sauerからのコメントの後に編集された)のキーとして使ってみてください、そうすればあなたは問題に直面し始めるでしょう。契約はガイドラインであり、あなたに強いられるものではありません。


  • 「持っている必要があります」 => 「持っている必要があります」、「あなたはキーHashMapの中で。 - Joachim Sauer

3

見てHashtablesHashmapsHashSetsなどなど。彼らは皆ハッシュキーを彼らのキーとして保存します。起動時get(Object key)パラメータのハッシュが生成され、与えられたハッシュで検索されます。

上書きしない場合hashCode()そして、キーのインスタンスが変更されている(例えば、まったく問題にならない単純な文字列)、hashCode()同じオブジェクトに対して2つの異なるハッシュコードが生成される可能性があります。map.get()

リンクされた質問


関連する質問

最近の質問