HashMap源碼閱讀(2)-put操做

1java

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
    int h;
    //k求的hashCode後, 高16位和低16位作異或運算(同則0,異則1,11->0,00->0, 10->1)
    //爲何呢?減小碰撞.
    //爲何能減小碰撞?
    /*
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null)
     */
    // n 是2的冪次方, 所以n-1的二進制,除了符號位是0,其餘都是1; 由於作&運算後結果的離散性,取決於hash值的離散性
    // 生活中都有規律,使用的key要麼通常偏小(整型,可能是short),要麼偏大(長字符串的hash). 高低8位作異或,打破規律.(本身胡謅的.......)
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //無符號右移16位,高位補0
  //  111111111 11111111 11111111 11111111 ^ 00000000 00000000 00000000 01111001
    //
}
/*
1 首次插入,要初始化table,分配空間
2 是否有碰撞:
    a 無,則插入
    b 有,則須要遍歷鏈表(或紅黑樹)查找是否存在相同的key [ 碰撞耗費性能 ]
       ba: 存在相同的key-> 替換
       bb: 不存在相同的key,插入尾部
 */
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;

    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;// 1 HashMap是lazy的.第一次put時,才調用resize,初始化table,分配空間
    // 若是未發生碰撞
    if ((p = tab[i = (n - 1) & hash]) == null) //用&運算來求餘,提升效率
        tab[i] = newNode(hash, key, value, null);
    else { //若是發生碰撞
        Node<K,V> e; K k;
        if (p.hash == hash && // 若是key的hash值相同,且equals(或同一內存地址->同一對象)
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p; //對value進行替換
        // 若是是紅黑樹節點
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            //若是是鏈表,遍歷鏈表
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {//到了鏈表末尾
                    p.next = newNode(hash, key, value, null);//鏈表末尾新增一個節點
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);// 鏈表節點數超過閾值,將其轉換成爲紅黑樹
                    break;
                }

                // 遍歷鏈表,查找是否有key相同的元素
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break; //若是有,則break, 此時e爲key相同的節點
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value; // 對value作替換
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue; //返回舊的value
        }
    }
    ++modCount;//對修改次數加1
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}
相關文章
相關標籤/搜索