- capacity <<= 1:
int i = 1;
//類似于 i++就是 i = i+1;的這結構
//i = i<<1 i等于i乘以2的1次方
//i <<= 1;
//i = i<<2 i等于i乘以2的2次方,>>就是相除了
i <<= 2;
System.out.println("結果是:" + i);
- java中有三種移位運算符:
// <<:左移運算符,num << 1,相當于num乘以2
// >>:右移運算符,num >> 1,相當于num除以2
// >>>:無符號右移,忽略符號位,空位都以0補齊
無符號右移的規則只記住一點:忽略了符號位擴展,0補最高位 無符號右移運算符>>> 只是對32位和64位的值有意義
//保證hashCode 不同的算法
//int 是4位byte的 4*8=32bit ,注意-->12+20=32
//h>>>20是無符號右移運算,就是將int類型的h的二進制數字位往右移動,左邊移出來的空位補上0。
//即為h = h ^ ((h >>> 20) ^ (h >>> 12));按位異或運算,僅當兩個對應的二進制位不相同時,結果為1;否則結果為0。
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
- 什么是哈希沖突:
- 哈希計算就是努力的把比較大的數據存放到相對較小的空間中。最常見的哈希算法是取模法。
- 取模法:數組的長度是5。這時有一個數據是6。那么如何把這個6存放到長度只有5的數組中呢。按照取模法,計算6%5,結果是1,那么就把6放到數組下標是1的位置。那么,7就應該放到2這個位置。到此位置,沖突還沒有出現。這時,有個數據是11,按照取模法,11%5=1,也等于1。那么原來數組下標是1的地方已經有數了,是6。這時又計算出1這個位置,那么數組1這個位置,就必須儲存兩個數了。這時,就叫哈希沖突。沖突之后就要按照順序來存放了。
- 如果數據的分布比較廣泛,而且儲存數據的數組長度比較大。那么哈希沖突就比較少。否則沖突是很高的。
HashMap就是一個散列表,它是通過“拉鏈法”解決哈希沖突的
- 什么是拉鏈法:
- 拉鏈法又叫鏈地址法,拉鏈法就是把具有相同散列地址的關鍵字(同義詞)值放在同一個單鏈表中,稱為同義詞鏈表。有m個散列地址就有m個鏈表,同時用指針數組T[0..m-1]存放各個鏈表的頭指針,凡是散列地址為i的記錄都以結點方式插入到以T[i]為指針的單鏈表中。T中各分量的初值應為空指針.
- 簡單來說拉鏈法就是數組加鏈表。
- 大方向上,HashMap 里面是一個數組,然后數組中每個元素是一個單向鏈表。
下圖中,每個綠色的實體是嵌套類 Entry 的實例,Entry 包含四個屬性:key, value, hash 值和用于單向鏈表的 next。
這個僅僅是示意圖,因為沒有考慮到數組要擴容的情況
從HashMap的實現來看,我們總結拉鏈法的實現步驟如下:
1. 計算 key 的 hashValue
2. 根據 hashValue 值定位到 table[hashIndex] 。( table[hashIndex] 是一條鏈表Node)
3. 若 table[hashValue] 為空則直接插入,不然則添加到鏈表末尾