web-dev-qa-db-ja.com

HashTableとHashMapのKey-Valueはどのようにメモリに保存されますか?

キーにその値をメモリアドレスに格納するために適用されるハッシュ手法があることを理解しています。

しかし、私にはわかりません衝突がどのように起こっているのかここで? どのハッシュアルゴリズムがJavaメモリスペースの作成に使用します?それはMD5ですか?

14
Sahal

HashMapの基本的な考え方は次のとおりです。

  1. HashMapは、実際にはKeyとValueの両方を保持する特別なオブジェクトの配列です。
  2. 配列には、16などのバケット(スロット)がいくらかあります。
  3. ハッシュアルゴリズムは、すべてのオブジェクトが持つhashCode()メソッドによって提供されます。したがって、新しいClassを作成するときは、適切なhashCode()およびequals()メソッドの実装に注意する必要があります。 (Objectクラスの)デフォルトのものは、メモリポインタを数値として受け取ります。しかし、それは私たちが使用したいほとんどのクラスにとっては良くありません。たとえば、Stringクラスは、文字列内のすべての文字からハッシュを作成するアルゴリズムを使用します。次のように考えてください:_hashCode = 1.char + 2.char + 3.char..._(簡略化)。したがって、2つの等しい文字列は、メモリ内の異なる場所にある場合でも、同じhashCode()を持ちます。
  4. hashCode()の結果、たとえば「132」は、そのような大きな配列がある場合にオブジェクトを格納するバケットの数になります。しかし、そうではありません。私たちのバケツの長さはわずか16です。したがって、明らかな計算_'hashcode % array.length = bucket'_または_'132 mod 16 = 4'_を使用して、キーと値のペアをバケット番号4に格納します。
    • 他のペアがまだない場合は、問題ありません。
    • キーが私たちが持っているキーと等しいものがある場合、古いものを削除します。
    • 別のKey-Valueペア(衝突)がある場合は、古いものの後に新しいものをリンクリストにチェーンします。
  5. バッキング配列がいっぱいになりすぎて、リンクリストを作成しなければならない場合は、長さを2倍にした新しい配列を作成し、すべての要素を再ハッシュして新しい配列に追加してから、古い配列を破棄します。これはおそらくHashMapで最もコストのかかる操作であるため、以前に知っていれば、使用するバケットの数をMapsに伝えたいと思います。
  6. 誰かが値を取得しようとすると、彼はキーを提供し、それをハッシュして変更し、完全に一致する可能性のあるリンクリストを調べます。

画像、ウィキペディア提供: The graphics

この場合、

  • 256個のバケットを持つ配列があります(もちろん、0から255までの番号が付けられています)
  • 5人います。それらのハッシュコードは、_mod 256_を通過した後、配列内の4つの異なるスロットを指します。
  • サンドラディーには空きスロットがなかったので、ジョンスミスの後にチェーンされていることがわかります。

ここで、サンドラディーの電話番号を検索しようとすると、彼女の名前をハッシュし、256で変更して、バケット152を調べます。そこにジョンスミスがいます。それはサンドラではありません、さらに見てください...ああ、ジョンの後にチェーンされたサンドラがいます。

30
Petr Janeček

ここで、HashHashingMD5 などの手法を意味するものではありません。その HashCode は、特定のキーのObjectを格納するために使用されるメモリ位置です。

読み:

This HashMapがどのように機能するかについて、もう少し明確に説明していますか?

4
Asif

デフォルトの実装として、ObjectクラスのhashCode()関数は、HashTableHashMapのキーとして使用されるハッシュとしてメモリアドレスを返します。

1
ejb_guy

@Slanecの回答を確認した後、重要な変更があるため、Java-8のjavadocを参照してください。例:「TREEIFY」。バケットあたりのエントリ数のしきい値(現在は8)に達した場合に、LinkedListがTreeMapに変換されます。

0
Biman Tripathy