「オン/オフトピック」の灰色の領域に入りますが、ハッシュコリジョンを増やすことはHashMap内の要素の数を減らすので良いことであるというOscar Reyesの提案に関する混乱を避けるために必要です。私はオスカーが言っていることを誤解しているかもしれませんが、私だけではないようです:kdgregory、delfuego、Nash0、そして私はすべて同じ(誤)理解を共有しているようです。
オスカーが同じハッシュコードの同じクラスについて言っていることを理解している場合、彼は、特定のハッシュコードを持つクラスの1つのインスタンスのみがHashMapに挿入されることを提案しています。たとえば、ハッシュコードが1のSomeClassのインスタンスと、ハッシュコードが1のSomeClassの2番目のインスタンスがある場合、SomeClassのインスタンスが1つだけ挿入されます。
http://pastebin.com/f20af40b9にある Javaペーストビンの例は、上記がオスカーの提案を正しく要約していることを示しているようです。
かかわらず、任意の理解や誤解のか、何が起こるかは、同じクラスの異なるインスタンスはないですありません、キーが等しいか否か判断だないまで-彼らは同じハッシュコードを持っている場合にHashMapに一度だけ挿入されます。ハッシュコードコントラクトでは、等しいオブジェクトに同じハッシュコードが必要です。ただし、等しくないオブジェクトが異なるハッシュコードを持っている必要はありません(これは他の理由で望ましい場合があります)[1]。
pastebin.com/f20af40b9の例(オスカーは少なくとも2回参照)を以下に示しますが、printlinesではなくJUnitアサーションを使用するように少し変更されています。この例は、同じハッシュコードが衝突を引き起こし、クラスが同じである場合に1つのエントリのみが作成されるという提案をサポートするために使用されます(たとえば、この特定のケースでは1つの文字列のみ)。
@Test
public void shouldOverwriteWhenEqualAndHashcodeSame() {
String s = new String("ese");
String ese = new String("ese");
// same hash right?
assertEquals(s.hashCode(), ese.hashCode());
// same class
assertEquals(s.getClass(), ese.getClass());
// AND equal
assertTrue(s.equals(ese));
Map map = new HashMap();
map.put(s, 1);
map.put(ese, 2);
SomeClass some = new SomeClass();
// still same hash right?
assertEquals(s.hashCode(), ese.hashCode());
assertEquals(s.hashCode(), some.hashCode());
map.put(some, 3);
// what would we get?
assertEquals(2, map.size());
assertEquals(2, map.get("ese"));
assertEquals(3, map.get(some));
assertTrue(s.equals(ese) && s.equals("ese"));
}
class SomeClass {
public int hashCode() {
return 100727;
}
}
ただし、ハッシュコードは完全な話ではありません。ペーストビンの例で無視されているのは、両方s
とese
が等しいという事実です。どちらも文字列「ese」です。したがって、s
or ese
またはor "ese"
をキーとして使用したマップのコンテンツの挿入または取得は、すべて同等です。s.equals(ese) && s.equals("ese")
。
2番目のテストは、同じクラスの同一のハッシュコードが、テスト1でが呼び出さs -> 1
れたese -> 2
ときにkey- >値が上書きされる理由であると結論付けることが誤っていることを示していますmap.put(ese, 2)
。テスト2では、s
とese
まだ同じハッシュコードを持つ(によって確認されるようにassertEquals(s.hashCode(), ese.hashCode());
)、彼らは同じクラスです。しかし、s
とese
しているMyString
。この試験でインスタンスしないのJava String
インスタンス-この試験に等しいことに関連する唯一の違いを有する:String s equals String ese
上記試験いずれかで、一方、MyStrings s does not equal MyString ese
試験2において:
@Test
public void shouldInsertWhenNotEqualAndHashcodeSame() {
MyString s = new MyString("ese");
MyString ese = new MyString("ese");
// same hash right?
assertEquals(s.hashCode(), ese.hashCode());
// same class
assertEquals(s.getClass(), ese.getClass());
// BUT not equal
assertFalse(s.equals(ese));
Map map = new HashMap();
map.put(s, 1);
map.put(ese, 2);
SomeClass some = new SomeClass();
// still same hash right?
assertEquals(s.hashCode(), ese.hashCode());
assertEquals(s.hashCode(), some.hashCode());
map.put(some, 3);
// what would we get?
assertEquals(3, map.size());
assertEquals(1, map.get(s));
assertEquals(2, map.get(ese));
assertEquals(3, map.get(some));
}
/**
* NOTE: equals is not overridden so the default implementation is used
* which means objects are only equal if they're the same instance, whereas
* the actual Java String class compares the value of its contents.
*/
class MyString {
String i;
MyString(String i) {
this.i = i;
}
@Override
public int hashCode() {
return 100727;
}
}
後のコメントに基づいて、オスカーは彼が以前に言ったものを逆転させるようで、平等の重要性を認めます。ただし、等しいという概念は重要であり、「同じクラス」ではなく、明確ではないようです(強調は私のものです)。
「実際にはそうではありません。リストはハッシュが同じで、キーが異なる場合にのみ作成されます。たとえば、文字列がハッシュコード2345を与え、整数が同じハッシュコード2345を与える場合、整数はリストに挿入されます。 equals(Integer)はfalseです。ただし、同じクラスがある場合(または少なくとも.equalsがtrueを返す場合)、同じエントリが使用されます。たとえば、new String( "one")と `new String(" one ")は、キーは、同じエントリを使用します。実際には、これが最初のHashMapの完全なポイントです!自分で確認してください:pastebin.com/f20af40b9 – Oscar Reyes "
同等の記述がない、同一のクラスと同じハッシュコードの重要性を明示的に扱う以前のコメントとの比較:
「@delfuego:自分で確認してください:pastebin.com/f20af40b9したがって、この質問では同じクラスが使用されています(ちょっと待って、同じクラスが正しく使用されていますか?)これは、同じハッシュが同じエントリで使用されていることを意味しますが使用され、エントリの「リスト」がありません。– Oscar Reyes "
または
「実際には、これによりパフォーマンスが向上します。衝突が多いほどeqハッシュテーブルのエントリが少ないeq。実行する作業が少なくなります。ハッシュ(見栄えが良い)でも、ハッシュテーブル(うまく機能する)でもありません。オブジェクトにあると思いますパフォーマンスが低下している作品–オスカー・レイエス」
または
"@kdgregory:はい、ただし、異なるクラスで衝突が発生した場合のみ、同じクラス(この場合)に同じエントリが使用されます。–オスカーレイエス"
繰り返しになりますが、オスカーが実際に言おうとしていたことを誤解しているかもしれません。しかし、彼の最初のコメントは十分な混乱を引き起こし、いくつかの明示的なテストですべてをクリアすることが賢明であるように思われるので、疑いの余地はありません。
[1] -Joshua BlochによるEffective Java、Second Editionから:
アプリケーションの実行中に同じオブジェクトで2回以上呼び出される場合、オブジェクトのequals比較で使用される情報が変更されていなければ、hashCodeメソッドは常に同じ整数を返す必要があります。この整数は、アプリケーションのある実行から別の実行への一貫性を保つ必要はありません。
equal s(Obj ect)メソッドに従って2つのオブジェクトが等しい場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、同じ整数の結果が生成される必要があります。
equal s(Object)メソッドに従って2つのオブジェクトが等しくない場合、2つのオブジェクトのそれぞれでhashCodeメソッドを呼び出すと、異なる整数の結果が生成される必要はありません。ただし、プログラマは、等しくないオブジェクトに対して異なる整数の結果を生成すると、ハッシュテーブルのパフォーマンスが向上する可能性があることに注意する必要があります。