web-dev-qa-db-ja.com

hashcode()をオーバーライドせずにHashTableを使用する

今日、私はインタビュー中にこの質問をされました:

クラスのhashcodeメソッドをオーバーライドせずにHashTableに追加してオブジェクトを取得しようとするとどうなりますか?

何がうまくいかないのでしょうか?

7
VextoR

オブジェクトを取得しようとするときのHashTableのアイデアは、データ構造がGetHashCode()メソッドを使用してオブジェクトのハッシュコードを計算し、次にEquals() 方法。

デフォルトのGetHashCode()実装では、完全に類似した2つのオブジェクトが異なるハッシュコードを生成する可能性があります。つまり、まったく同じインスタンスを使用しないと、HashTableでオブジェクトが見つかりません。 。

一般に、ハッシュコードを実装するときは、次の2つのことを確認する必要があります。

  • もしA.Equals(B)ならA.GetHashCode()==B.GetHashCode()
  • ハッシュコードの分布を適切に広げて、ハッシュテーブルから最大の効率を得るようにしてください(ハッシュコードが少なすぎると、リストを検索することになります)。
18
SRKX

クラスのハッシュコードメソッドをオーバーライドせずにHashTableに追加してオブジェクトを取得しようとするとどうなりますか?

「HashTableへの追加」の意味によって異なります。 Javaの Hashtable にはaddメソッドがありません。インタビュアーはおそらくputメソッドを意味し、keyvalue。値は任意です(HashMapの現在のバージョンであるHashMapではnullにすることもできます)。値オブジェクトのハッシュコードやその他のメソッドをオーバーライドするかどうかに関係なく、特別なことは何も起こりません。

インタビュアーはおそらく、キーオブジェクトのハッシュコードが上書きされないことを意味しました。そうして初めて、他の回答で指摘されているように、オブジェクトのアイデンティティの問題が発生します。それでも、必ずしもキーのハッシュコードをオーバーライドする必要はありません。たとえば、Stringsをキーとして使用する場合、それらにはすでに適切なハッシュコード実装が含まれています。さらに、それらはサブクラス化できません。さらに、doがハッシュコードをオーバーライドするが、しないオーバーライドが等しい場合、あなたはいくつかの驚くべき行動をするかもしれません...

質問が本当にあなたが書いたものであった場合、私はこれらの質問で面接官をからかったでしょう。優れたプログラマーは、インタビュアーがおそらくこれを意味しているとは思わない。代わりに彼は尋ねます。

6
Joonas Pulakka

答えは、「equals()をオーバーライドしない限り問題ありません」です。

一般的なポイントは、2つのオブジェクトが等しい場合、つまり

_ a.equals(b)
_

次に、それらは同じハッシュコードを持っている必要があります。

_ a.hashCode() == b.hashCode()
_

また、2つのオブジェクトのハッシュコードが異なる場合、それらを等しく比較してはなりません。

これは、オブジェクトをハッシュテーブルに配置する場合に特に重要です。これは、ハッシュテーブルがリストの配列(通常はバケットと呼ばれます)であるためです。ハッシュバケットにはハッシュコードを使用してインデックスが付けられ、通常は_hashCode % arraySize_を使用します。

したがって、ハッシュテーブルにオブジェクトを配置するときは、キーのハッシュコードを取得し、それを使用してバケットを決定します。次に、キーと値のペアをバケットに入れます。ハッシュテーブルからオブジェクトを取得する場合は、キーのハッシュコードを取得してバケットを見つけ、.equals()を使用してバケット内のすべてのキーと値のペアのキーをテストし、どのオブジェクトかを判別しますあなたが欲しいものです。

したがって、等しいがハッシュコードが異なる2つのキーオブジェクトがあり、1つをハッシュテーブルのキーとして使用する場合、他のキーオブジェクトを使用してそれを検索することはできません。間違ったバケツ。

Object内のequals()の実装は、2つのオブジェクトが実際に同じオブジェクトであり、hashCode()がオブジェクト参照を返す場合にのみtrueを返します。ただし、equals()をオーバーライドする場合(たとえば、文字列により、同じ文字シーケンスを含む異なる文字列が同じになるように比較されます)、hashCode()をオーバーライドする必要があります

6
JeremyP

配置したオブジェクトとequalである別のオブジェクトを取得した場合、そのオブジェクトは見つかりません

または例を挙げます:

MyClass obj1 = new MyClass(1);
MyClass obj2 = new MyClass(1);
assert obj1.equals(obj2);
assert obj1.hashcode()!=obj2.hashcode(); //this is wat happens if you don't inclde hashcode
table.put(obj1,2);
table.get(obj2) // will likely return null but that is a gamble
table.get(obj1) // but this will return the object passed in

これは、HashTable(およびHashMap)がハッシュコードを使用してオブジェクトを検索するために検索する必要があるスペースを制限し、obj1.equals(obj2)の場合にobj1.hashcode == obj2.hashcode()であるという仮定に依存するためです。

4
ratchet freak

これらの概念はすべてidentityおよびcomparisonに関連していることを付け加えておきます。

ハッシュコードとの契約があります:

1.)Javaアプリケーションの実行中に同じオブジェクトで2回以上呼び出される場合は常に、hashCodeメソッドは常に同じ整数を返す必要があります。ただし、オブジェクトは変更されます。この整数は、アプリケーションのある実行から別の実行への一貫性を保つ必要はありません。

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

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

結局のところ、ハッシュコードが同じである場合、テーブル内のエントリは互いに上書きし、一部のユーザーには意外となる可能性があります...

お役に立てれば。

3
rich_markle

答えは次のとおりです。類似したオブジェクト(すべてのフィールドの値が等しい)は同じハッシュコードを作成しないため、putがハッシュテーブルから取得するために使用されたものとまったく同じ(同一の)オブジェクトが必要です。ほとんどの場合実行可能です。

2
user281377

クラスがObjectのみを拡張すると仮定すると、クラスのhashCode()実装は、オブジェクトIDに依存します。つまり2つの異なるインスタンスのハッシュコードは、正確に同じ値を保持していても、(ほぼ確実に)異なることに注意してください。

これは、マップ内でオブジェクトを再び見つけられない可能性が最も高いことを意味します(ただし、might偶然にオブジェクトを見つける可能性があります)。

2
Joachim Sauer

ハッシュコードメソッドがオーバーライドされていない場合、この質問への答えは、実際に"put"に使用されたのと同じキーオブジェクトが"get"にも使用されるかどうかに依存します。

a)同じキーオブジェクトが使用されている場合-"get"は値を検索します。同じ"key"を使用してバケットを検索し、値オブジェクトを見つけるためです。

b)別の「同等の」キーオブジェクトが使用されている場合-Objectのハッシュコードメソッドのデフォルトの実装によりハッシュコードが異なる可能性があるため、別のバケットに入れられない可能性があります。値オブジェクトを取得できます。

1
java_mouse