1. 程式人生 > >java原始碼解讀之HashMap

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的擴容是怎麼操作的,擴容後元素是如何保障均勻分佈的