Hashmap 源碼分析

Hashmap 源碼分析

  • put()null的處理,重複key的處理,hash衝突的鏈表處理
  • indexfor() hash算法從而獲得槽點的巧妙用處


 public V put(K key, V value) {

     //空表處理
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        //null處理,因爲hanshmap允許傳入null
        if (key == null)
            return putForNullKey(value); 
    ------int hash = hash(key);//參數key 進行hash,返回 hash值
    | ----- int i = indexFor(hash, table.length);//得到bucket的槽點
    |   
        /**
        循環遍歷,找到合適位置插入,可以看到e ==null 跳出循環,存儲Entry<key,value>對象
           e!=null  hash衝突, e = e.next 這裏是解決hash衝突的關鍵,我們叫做拉鍊法,增加了一個表存儲Entry<key,value>對象
        舉個例子大家就懂了:
        第一個鍵值對A進來,通過計算其key的hash得到的index=0,記做:Entry[0] = A。
        一會後又進來一個鍵值對B,通過計算其index也等於0,現在怎麼辦?
             HashMap會這樣做:B.next = A,Entry[0] = B,如果又進來C,index也等於0,
        那麼C.next = B,Entry[0] = C;這樣我們發現index=0的地方其實存取了A,B,C三個鍵值對,
       他們通過next這個屬性鏈接在一起
        */
    |   for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    |      Object k;
    |        //重複key,覆蓋原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);//合適位置插入了Entry<key,value>對象
    |    return null;
    |  }
    |
    |
     //hashmap的hash方法,可以看到調用了 native hashcode方法,中間算法太過複雜,不作深入研究
    |
    |--➡️ final int hash(Object k) {
    |    int h = hashSeed;
    |    if (0 != h && k instanceof String) {
    |        return sun.misc.Hashing.stringHash32((String) k);
    |    }
    |
    |    h ^= k.hashCode();
    |
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
       h ^= (h >>> 20) ^ (h >>> 12);
    |    return h ^ (h >>> 7) ^ (h >>> 4);
    |   }
    |
    |  //一個靜態方法,得到槽點
    |---➡️   static int indexFor(int h, int length) {
        //這裏源碼的註釋是傳入的length必須爲 非零2的冪,爲什麼要這麼規定呢?看下面
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";

        /**
        & 與運算符(0 0 爲0 ,1 0 爲 0,1 1 爲1),
        2的冪的二進制有基礎的同學可以發現它的二進制前幾位都是0,
        這麼做的後果是hash值 h 與length進行 &運算始終是<= length-1 的,
        最後返回key的槽點值

        */
        return h & (length-1);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章