2015-10-16 8 views
6

this blog entryによると、HashMapはすでに検索したハッシュコードに対してhashCode()という独自の実装(hash())を再表示します。キーがNULLでない場合key.hashCodeは()ハッシュ値を返した後、4行目はHashMapにはhash()という独自のhashCode()が実装されています。

のように見えるよう

、それは、上記の方法すなわちkey.hashCode()でライン4を参照して、キーオブジェクトにハッシュ関数を呼び出します

int hash = hash(hashValue)

これで、返されたhashValueが独自のハッシュ関数に適用されます。

ハッシュ値(ハッシュ値)を使用してハッシュ値を再度計算する理由が不思議に思うかもしれません。答えは、それは劣悪な品質のハッシュ関数を守ることです。

HashMap 正確にハッシュコードを再割り当てできますか? HashMapはオブジェクトを格納できますが、そのオブジェクトにhashCodeを割り当てるロジックにはアクセスできません。たとえば、hash()は、おそらく以下hashCode()実装の背後にあるロジックを統合することができませんでした:hash()実際のハッシュコードから「改善」のハッシュコードを導出

public class Employee { 
protected long employeeId; 
protected String firstName; 
protected String lastName; 

public int hashCode(){ 
    return (int) employeeId; 
} 

} 
+3

可能な複製(http://stackoverflow.com/questions/9335169/understanding-strange-java-hash-function) – Nayuki

+1

は(ハッシュ 'の実装を推測@NayukiMinase)' 1.8.0_51バージョンが異なる/よりシンプルであるため、時間の経過と共に変化しました(私の答えを見てください)。 – Andreas

答えて

13

ので、同じ入力は常にjdk1から等しい出力(あろう.8.0_51):

static final int hash(Object key) { 
    int h; 
    return (key == null) ? 0 : (h = key.hashCode())^(h >>> 16); 
} 

ハッシュコードが改善を必要とする理由として、方法のJavadocを読み取る:

計算key.hashCodeを()AN dはハッシュの上位ビットを拡散(XOR)して下げる。このテーブルは2のべき乗マスキングを使用しているため、現在のマスクの上のビットだけが変化するハッシュのセットは常に衝突します。 (よく知られている例の中には、小さなテーブルに連続する整数を保持するFloatキーのセットがあります)。したがって、上位ビットの影響を下方向に広げる変換を適用します。速度、効用、ビット拡散の品質にはトレードオフがあります。多くの一般的なハッシュセットはすでに合理的に配布されているため(拡散の恩恵を受けません)、ビン内の大きな衝突セットを処理するためにツリーを使用するため、システム損失を最小限に抑えるために、また、テーブル境界のためにインデックス計算に使用されない最高ビットの影響を組み込むことができます。 [奇妙なJavaのハッシュ関数を理解する]の

+2

別の言い方をすると、 'HashMap'クラスはオブジェクトから生の' hashCode() '値を受け取り、1対1の「ホワイトニング」変換を適用して分布をより均一にしようとします。 – Nayuki

+0

@アンドレアス私は解決策を受け入れた!ありがとう。あなたは私にリンクしたり、おそらく説明して、2のべき乗マスキングは何ですか?タームのためのGoogleの検索は、ゼロを生成しました。 – Muno

+1

@Muno 2のべき乗マスキングは、ハッシュテーブルサイズが常に2の累乗(2,4,8,16,32、...)であるという事実を指します。したがって、ハッシュテーブルバケットを計算するには、単純なビットマスク演算でモジュラス演算( '%')よりも速い(例えば、ハッシュテーブルサイズ32の場合は 'h&0x1F')。 – Andreas

関連する問題