(1) JavaのhashCode()で31を掛け算する理由について
(1-1) ハッシュの計算のソースコード
(1-2) ソースコードに登場する代表的な変数
(1-3) ソースコード解説
(1) JavaのhashCode()で31を掛け算する理由について
Javaでハッシュを計算するhashCode()について、実際のプログラムを見てみると「31」で掛け算する計算を行っていますが、今日はこの「31の意味」について書きたいと思います。
(1-1) ハッシュの計算のソースコード
以下がStringクラスのhashCode()メソッドのソースコードです。Eclipseなどで「[String変数].hashCode()」の部分を右クリックして「Open Declaration」を押下すると、hashCodeメソッドのソースコードを見る事ができます。
(ソースコード)
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
(図111)Open Declaration

(1-2) ソースコードに登場する代表的な変数
ソースコードを理解するために、まず代表的な変数の意味を抑えます。
(表)
| 項目 | 説明 |
| hash | ハッシュ値を保持するための変数です。これはStringクラスのメンバ変数として下記のように定義されているものです。
private int hash; // Default to 0 初期値は「0」ですが、一回計算するとその結果が格納されるため、次回以降に同じ文字列に対しては値が入った状態になります。 |
| value | 文字列の各文字を1文字ずつ保持するためのchar型の配列です。これはStringクラスのメンバ変数として下記のように定義されているもので、文字列の生成時に値が入ります。
private final char value[] |
(1-3) ソースコード解説
先ほどのソースコードにコメントを追記したバージョンを掲載します。ただし「h = 31 * h + val[i];」の部分は難しいので、コードの後の(補足)欄で更に補足します。
(ソースコード)
public int hashCode() {
//前回の計算結果(hash)をhに格納
int h = hash;
//前回の計算結果が0(なし) AND 文字列長>0(文字列あり)の場合
if (h == 0 && value.length > 0) {
//文字列をchar型の配列に格納(1文字ずつ計算に当てはめるため)
char val[] = value;
//文字列長の長さ(文字数)だけループ
for (int i = 0; i < value.length; i++) {
// 31 * h => 1つ前のループまでの結果×31倍
// + val[i] => 次の文字の10進数のASCIIコードを加算
// (char型は足し算する時は整数とみなされる性質を利用)
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
h[n] = 31 * h[n-1] + val[n-1] ・・・(★)
= 31 * (31 * h[n-2] + val[n-2]) + val[n-1]
= 31 * (31 * (31 * h[n-3] + val[n-3]) + val[n-2]) + val[n-1]
= 31 * (31 * (31 * (31 * h[n-4] + val[n-4]) + val[n-3]) + val[n-2]) + val[n-1]
・・・(続く)
= val[0]*31^(n-1) + val [1]*31^(n-2) + ... + val [n-1] ・・・(▲)
(5ビットシフトして元の数を引く)
31 * i == (i << 5) - i