hjr-java源碼:HashMap

理解

  • 散列算法:把多個數據用少量數據標記出來
  • hashing(哈希):標記是hashcode的散列算法

HashMap的結構是

包含多個HashCode的數組,每個HashCode對應一個Bucket(桶),每個桶是一個LinkList(鏈表),鏈表裏面存儲的是多個Entry(鍵值對+next+hash值)

數組中存取值 通過如下算法:

// 存儲時:
int hash = key.hashCode(); 
int index = hash % Entry[].length;
Entry[index] = value;

// 取值時:
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];

HashMpa.put(對象)

對象就是一個Entry,程序員控制鍵值對的內容,next和hash會自動生成

  • 碰撞:當系統給兩個Entry生成的hash相同時就會發生碰撞,最後Entry,會存儲到相同hash對應的鏈表裏,其中 next,就是標記多個相同hash的Entry 之間的鏈表連接關係的。

next和hash是怎麼自動生成的?

  • put()
    當程序員put一個Entry時,先使用Hash函數計算出下數組下標,確定這個Entry插入到hashcode數組的哪個位置
public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value); //null總是放在數組的第一個鏈表中
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        //遍歷鏈表
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            //如果key在鏈表中已存在,則替換爲新value
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }


void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //參數e, 是Entry.next
    //如果size超過threshold,則擴充table大小。再散列
    if (size++ >= threshold)
            resize(2 * table.length);
}

  • get()
public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        //先定位到數組元素,再遍歷該元素處的鏈表
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
}

根據Key值做一次Hash映射,算出其對應的數組下標值,
碰撞問題,同一個位置的鏈表裏可能存在多個Entry,這時就要從對應鏈表的頭節點開始,一個個向下查找,直到找到對應的
Key值,這樣就獲得到了所要查找的鍵值對

  • hashcode數組的長度?
    有一個初始長度16,每當觸發到75%,長度擴大一倍,然後把之前的數組全部數據移動到新數組中。

  • hashmap死鎖
    在多線程的情況下,當重新調整HashMap大小的時候,就會存在條件競爭,因爲如果兩個線程都發現HashMap需要重新調整大小了,它們會同時試着調整大小

使用hashtable(完全同步)和currentHashMap(分片同步)等線程安全的可以避免死鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章