HashCode的祕密

看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 value="abcd"; 那麼其計算結果爲:
value[0]=a;
h=31*0+a;     --31*0+97
 =a;          --97
value[1]=b;
h=31*(31*0+a)+b;     --31*97+98
 =31*a+b;            --3007+98=3105
value[2]=31*(31*a+b)+c;    --96255+99
        =31*31*a+31*b+c;   --96354
value[3]=31*(31*31*a+31*b+c)+d       --31*96354+100
        =31*31*31*a+31*31*b+31*c+d   --2986974+100
h=31^(n-1)*value[0]+31^(n-2)*value[1]+31^(n-3)*value[2]+value[n-1];
 
 
進制轉換的表示方法爲:16進制的20表示成10進制就是:2×16¹+0×16º=32
那麼HashCode的計算方式就是字符的ascii碼 按照31進制的計算方式去計算。
-------------------------------------------------------------------------------------------
咱們會注意那個狗血的31這個係數爲何老是在裏面乘來乘去?爲何不適用32或者其餘數字?

你們都知道,計算機的乘法涉及到移位計算。當一個數乘以2時,就直接拿該數左移一位便可!選擇31緣由是由於31是一個素數!java

所謂素數:優化

質數又稱素數。指在一個大於1的天然數中,除了1和此整數自身外,無法被其餘天然數整除的數。spa

在存儲數據計算hash地址的時候,咱們但願儘可能減小有一樣的hash地址,所謂「衝突」。若是使用相同hash地址的數據過多,那麼這些數據所組成的hash鏈就更長,從而下降了查詢效率!因此在選擇係數的時候要選擇儘可能長(31 = 11111[2])的係數而且讓乘法儘可能不要溢出(若是選擇大於11111的數,很容易溢出)的係數,由於若是計算出來的hash地址越大,所謂的「衝突」就越少,查找起來效率也會提升。ci

31能夠 由i*31== (i<<5)-1來表示,如今不少虛擬機裏面都有作相關優化,使用31的緣由多是爲了更好的分配hash地址,而且31只佔用5bits!源碼

在java乘法中若是數字相乘過大會致使溢出的問題,從而致使數據的丟失.虛擬機

而31則是素數(質數)並且不是很長的數字,最終它被選擇爲相乘的係數的緣由不過與此!hash

如i*31==(i<<5)-1  用二進制表示就是:
1<<5  移位 位100000
11111==100000-1 
相關文章
相關標籤/搜索