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循環,有點搞吧?我來舉個例子,讓你很容易明白它在搞什麼名堂。比如有一個字元串“abcde”,采用31進制的計算方法來計算這個字元串的總和,你會寫出下面的計算式子:
a*31^4+b*31^3+c*31^2+d*31^1+e*31^0.注意,這裡的a,b,c,d或者e指的是它們的ascii值。很有趣的循環,居然可以用來算n進制。這個循環可以抽出來單獨作為計算進制的好工具:
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;
靜态方法caculate接受radix作為進制基數,數組a模拟要計算的進制的數字,隻是注意表面順序需要一緻。比如 01 二進制串,在數組中要按照{0,1}排列。上面的輸出結果是1,符合01的真實值。
那麼為什麼選用31作為基數呢?先要明白為什麼需要hashcode.每個對象根據值計算hashcode,這個code大小雖然不奢求必須唯一(因為這樣通常計算會非常慢),但是要盡可能的不要重複,是以基數要盡量的大。另外,31*n可以被編譯器優化為
認為這個東西還是會導緻較多的重複,應該用更大的數字。是以,或許将來java的實作中會有所變化。下面這篇文章介紹了兩個結論:
1.基數要用質數
質數的特性(隻有1和自己是因子)能夠使得它和其他數相乘後得到的結果比其他方式更容易産成唯一性(最終出來的結果隻能被素數本身和被乘數還有1來整除),也就是hash code值的沖突機率最小。
2.選擇31是觀測分布結果後的一個選擇,不清楚原因,但的确有利。
3.31可以 由i*31== (i<<5)-1來表示,現在很多虛拟機裡面都有做相關優化.(提高算法效率)
<a target="_blank" href="http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/">http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/</a>
另外,string.hashcode内部會緩存第一次計算的值,因為這是一個final(不可變)類,也就是string對象的内容是不會變的。這能夠在多次put到hashmap的場合提高性能,不過似乎用處不多。