この式を使用して、特定のキーのハッシュコードがどのように詳細に計算されるか
これの場合、次のように実装されてString
計算さString#hashCode();
れます。
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
基本的に、JavaDocの式に従います。
hashcode = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
この実装で注目すべき興味深い点の1つは、String
実際にハッシュコードをキャッシュすることです。String
は不変であるため、これを行うことができます。
String
「Amit」のハッシュコードを計算すると、次の整数になります。
System.out.println("Amit".hashCode());
> 2044535
マップへの簡単な配置を見てみましょうが、最初にマップがどのように作成されるかを決定する必要があります。Javaの最も興味深い事実は、JavaHashMap
には常に2^n個のバケットがあるということです。したがって、これを呼び出すと、バケットのデフォルト数は16であり、明らかに2^4です。
このマップでput操作を実行すると、最初にキーのハッシュコードが取得されます。貧弱なハッシュ関数(特に下位ビットが異ならないもの)が単一のバケットを「オーバーロード」しないようにするために、このハッシュコードでいくつかの凝ったビットの調整が行われます。
キーをバケットに配布する実際の機能は次のとおりです。
h & (length-1); // length is the current number of buckets, h the hashcode of the key
これは、モジュロではなく&を使用してキーをバケットにマップするため、2つのバケットサイズの累乗に対してのみ機能します。
「Amit」は、ビットがいじられるため、10番目のバケットに配布されます。少し調整がなければ、7番目のバケットに移動し2044535 & 15 = 7
ます。
インデックスができたので、バケットを見つけることができます。バケットに要素が含まれている場合は、それらを繰り返し処理し、見つかった場合は等しいエントリを置き換える必要があります。リンクリストにアイテムが見つからない場合は、リンクリストの先頭に追加します。
次に重要なのHashMap
はサイズ変更です。したがって、マップの実際のサイズがしきい値(現在のバケット数と負荷率によって決定されます。この場合は16 * 0.75 = 12)を超えると、バッキング配列のサイズが変更されます。サイズ変更は常に2*現在のバケット数です。これは、バケットを見つける機能を壊さないように2の累乗であることが保証されています。
バケットの数が変わるため、テーブル内の現在のすべてのエントリを再ハッシュする必要があります。これは非常にコストがかかるため、アイテムの数がわかっている場合は、HashMap
そのカウントで初期化して、全体のサイズを変更する必要がないようにする必要があります。