首先來看一下String中hashCode方法的實現源碼
1 public int hashCode() { 2 int h = hash; 3 if (h == 0 && value.length > 0) { 4 char val[] = value; 5
6 for (int i = 0; i < value.length; i++) { 7 h = 31 * h + val[i]; 8 } 9 hash = h; 10 } 11 return h; 12 }
在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方法判斷字符串相等或者字符串回文,都存在反例。