先上源碼:
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote> * using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return? a hash code value for this object.
*/
public int hashCode() {
int h =hash;
if (h ==0 &&value.length >0) {
char val[] =value;
for (int i =0; i
h =31 * h + val[i];
}
hash = h;
}
return h;
}
相信很多朋友跟我一樣,在查看String 類中hashCode() 方法具體實(shí)現(xiàn)的時(shí)候,會(huì)有個(gè)一疑問,為什么會(huì)有個(gè)常量系數(shù) 31,這個(gè)31是什么,怎么來的?有什么具體的含義;然后就各種查;
我也是簡(jiǎn)單的查了一下,網(wǎng)上的對(duì)這個(gè)解讀的資料還是蠻多的,很輕松的找到可答案;
整理了一下,主要是有一下幾種原因:
1、31是素?cái)?shù),素?cái)?shù)是什么?素?cái)?shù)也是質(zhì)數(shù),除了1和它本身以外,沒有其他因數(shù)。所以不能被其他自然數(shù)整除
2、在存儲(chǔ)數(shù)據(jù)計(jì)算hash地址的時(shí)候,我們希望相同的hash地址越少越好,也就是所謂的“沖突”,因?yàn)橄嗤膆ash地址的數(shù)據(jù)越多,生成的hash鏈表就越長(zhǎng),查找數(shù)據(jù)遍歷的時(shí)間就越長(zhǎng),從而降低了查詢效率。所以在選擇系數(shù)的時(shí)候,我們希望這個(gè)系數(shù)越大越好(hash地址越大,沖突的概率越小,查詢效率就高),但是相乘最好不要溢出(系數(shù)越大,越容易造成數(shù)據(jù)溢出,溢出的話,會(huì)造成數(shù)據(jù)的丟失)。而 31= 11111【二進(jìn)制】,只占5bits。
3、我們都知道,計(jì)算機(jī)的乘法涉及到移位計(jì)算,一個(gè)數(shù)*2直接將這位數(shù)往左移一位即可,31*i = 2^5 * i - i, 相當(dāng)于 i 向 左移動(dòng)5位,再減 i,這樣就轉(zhuǎn)化成移位和減法結(jié)合的計(jì)算,比直接相乘的速度更快。也算是對(duì)算法的一種優(yōu)化
綜合以上幾個(gè)原因,選擇了31這個(gè)系數(shù)。