首先來看一下String中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; }
在String中有一個私有實例字段hash表示該串的哈希值,在第一次調用hashCode方法時,字符串的哈希值被計算並且賦值給hash字段。之后再調用hashCode方法便可以直接取hash字段返回。
String類中的hashCode計算方法還是比較簡單的,就是一31為權,每一位字符的ASCII只進行計算,用自然溢出來等效取模。
哈希計算公式可以記為s[0]*31^(n-1)+s[1]*31^(n-2)+...+s[n-1]。
關於為什么取31為權,可以參考StackOverflow上的這個問題
主要原因是因為31是一個奇素數,所以31*i=32*i-i=(i<<5)-i,這種位移與剪發結合的計算相比一般的運算塊很多。
字符串哈希可以做很多事情,通常是類似於字符串判等,判回文之類的。
但是僅僅依賴於哈希值來判斷其實是不嚴謹的,除非能夠保證不會有哈希值沖突。通常這一點很難做到。
就拿jdk中String類的哈希方法來舉例,字符串“gdejicbegh”與字符串"hgebcijedg"具有相同的hashCode()返回值-801038016,並且他們具有reverse的關系。這個例子說明了用jdk中默認的hashCode方法判斷字符串相等或者字符串回文都存在反例。
