java原始碼解讀之HashMap
1:首先下載openjdk(http://pan.baidu.com/s/1dFMZXg1),把原始碼匯入eclipse,以便看到jdk原始碼
Windows-Preferences-Java-Installed JREs,選中相應的jdk,Edit-選中rt.jre,點選Source Attachment,在彈出的選單中選中單選按鈕External location,把下載好的原始碼導進來.(如圖)
2:HashMap概述
HashMap是基於雜湊表的Map介面的非同步實現,允許使用null值和null鍵,但不保障順序不變
3:HashMap的資料結構
HashMap實際是一個 連結串列雜湊 的資料結構,即陣列和連結串列的結合體
如圖:HashMap底層是一個數組結構,陣列的每一項又是一個連結串列.
Map<Object,Object> hashMap = new HashMap<>();//其中預設載入因子是0.75f,預設初始容量16,table是一個長度為16的陣列.
4:HashMap的存取實現
public V put(K key, V value) {
//當key為null時,呼叫putForNullKey(value);把value放入陣列第一個位置
if (key == null)
return putForNullKey(value);
//根據key的hashCode重新計算hash值
int hash = hash(key.hashCode());
//搜尋制定的hash值在table中的索引
int i = indexFor(hash, table.length);
//如果i索引處的entry不為null,通過迴圈不斷遍歷e的下一個元素
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//如果i索引處的Entry為null,表明此處還沒有Entry
modCount++;
//將K,V增加到i所引處
addEntry(hash, key, value, i);
return null;
}
從上面的原始碼中可以看出:當我們往HashMap 中put 元素的時候,先根據key 的hashCode 重新計算hash 值,根據hash 值得到這個元素在陣列中的位置(即下標),如
果陣列該位置上已經存放有其他元素了,那麼在這個位置上的元素將以連結串列的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果陣列該位置上沒有元素,就直接將該元素放到此陣列中的該位置上。
addEntry(hash, key, value, i)方法根據計算出的hash 值,將key-value 對放在陣列table的i 索引處.addEntry 是 HashMap 提供的一個包訪問許可權的方法,程式碼如下:
void addEntry(int hash, K key, V value, int bucketIndex) {
// 獲取指定 bucketIndex 索引處的 Entry
Entry<K,V> e = table[bucketIndex];
// 將新建立的 Entry 放入 bucketIndex 索引處,並讓新的 Entry 指向原來的 Entry
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
// 如果 Map 中的 key-value 對的數量超過了極限
if (size++ >= threshold)
// 把 table 物件的長度擴充到原來的2 倍。
resize(2 * table.length);
}
當系統決定儲存HashMap 中的key-value 對時,完全沒有考慮Entry 中的value,僅僅只是根據key 來計算並決定每個Entry 的儲存位置。我們完全可以把 Map 集合中的 value 當
成 key 的附屬,當系統決定了 key 的儲存位置之後,value 隨之儲存在那裡即可。
hash(int h)方法根據key 的hashCode 重新計算一次雜湊。此演算法加入了高位計算,防止低位不變,高位變化時,造成的hash 衝突。
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
------------------------------------------------------未完待續--------------------------------------
牛人的理解:http://blog.csdn.net/tuke_tuke/article/details/51588156
①訪問修飾符為什麼是16
java底層是C語言開發的,C語言底層是彙編(彙編使用的是16進位制),彙編來源於機器語言
②hashMap(陣列+連結串列+紅黑樹)
③hashmap的擴容是怎麼操作的,擴容後元素是如何保障均勻分佈的