ハッシュ計算は、配列に配置する要素を計算することです。正確には、リンクリストに配置されます。 Javaのルールによると、オブジェクトをハッシュマップに入れたい場合、オブジェクトのクラスはハッシュコードメソッドを提供し、整数値を返す必要があります。たとえば、文字列クラスには次の方法があります。
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; }上記のforループに注意を払ってください、それは少しめちゃくちゃではありませんか?それが何を作っているのかを理解しやすいように、例を挙げましょう。たとえば、31桁の計算方法を使用してこの文字列の合計を計算する文字列「ABCDE」があります。次の計算式を書きます。
a*31^4+b*31^3+c*31^2+d*31^1+e*31^0。ここでは、A、B、C、D、またはEがASCII値を参照することに注意してください。 n-digitの計算に使用できる非常に興味深いループ。このループは、パーティションを計算するための優れたツールとして別々に抽出できます。
public static void main(string [] args){int [] a = {1,0}; system.out.println(calculate(2、a)); } private static int calculate(int radix、int [] a){int sum = 0; for(int i = 0; i <a.length; ++ i){sum = sum*radix+a [i]; } return sum; }静的メソッドのCaciculateは、基数をカーディナリティとして受け入れ、Array Aが計算する計算の数をシミュレートし、一貫した表面順序に注意してください。たとえば、01バイナリ文字列は、{0,1}に従って配列に配置する必要があります。上記の出力は1で、01の真の値を満たしています。
では、なぜ31をベースとして使用するのですか?まず、ハッシュコードが必要な理由を理解する必要があります。各オブジェクトは、値に基づいてハッシュコードを計算します。このコードサイズには一意性は必要ありませんが(これは通常非常に遅くなるため)、可能な限り繰り返されないため、可能な限り繰り返されないようにするため、枢機inalはできるだけ大きくする必要があります。さらに、31*nはコンパイラによって最適化されて、左に5ビットをシフトし、1つ削減できます。これにより、パフォーマンスが高くなります。実際、31を選択することはまだ議論の余地があります。こちらを参照してください。
このことは依然としてより多くの繰り返しにつながり、より多くの数字を使用するはずだと思います。したがって、おそらく将来のJava実装にいくつかの変更があるかもしれません。次の記事では、2つの結論を紹介します。
1.カーディナリティに素数を使用します
素数の特性(1それ自体のみが要因)は、他の方法よりも一意性を生み出すことができる他の数字でそれを乗算することで得られる結果を得ることができます。つまり、ハッシュコード値間の競合の確率は最小です。
2。選択31は、分布の結果を観察した後の選択です。その理由は明確ではありませんが、実際に有益です。
さらに、最初に計算された値は内部でキャッシュされます。これは最終的な(不変の)クラスであるため、文字列オブジェクトのコンテンツは変更されません。これにより、ハッシュマップを複数回配置するとパフォーマンスが向上しますが、ほとんど役に立たないようです。
要約します
上記は、ハッシュコードを定義するときに31の係数が使用される理由についてのすべてです。私はそれが誰にでも役立つことを願っています。興味のある友達は引き続きこのサイトを参照できます:
「 HashCode()およびEquals()メソッドの書き換えの詳細な紹介」
「 HashCode()とEquals()の間の本質的な違いと接続の詳細な説明」
「ハッシュマップの使用に関するJavaソースコード分析」
欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!