HashMap:HashMap學習筆記

1、hash算法java

// jdk中hash方法
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    // hashMap中執行putVal的方法,截取一小段
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);


例如:
         // 取hash值,並轉換爲二進制
        int h = "test".hashCode();
        System.out.println(Integer.toBinaryString(h));

        // 將hash值右移16位
        int nh = h >>> 16;
        System.out.println(Integer.toBinaryString(nh));

        // 得到h與nh的異或的值
        int hash = h ^ nh;
        System.out.println(Integer.toBinaryString(hash));

輸出
        1101100100010010010010
        110110
        1101100100010010100100

32位補全整理以後
hashCode        0000 0000 0011 0110 0100 0100 1001 0010
右移16位後       0000 0000 0000 0000 0000 0000 0011 0110
前面兩個值異或    0000 0000 0011 0110 0100 0100 1010 0100
  • 先將傳入的值取hashCode值,記做h
  • 再將h右移16位,記做nh
  • 最後將h與nh進行異或就是最終結果hash
  • 將hash與15相與(即取模)得到索引位置index(計算索引的目的是爲了肯定該數據是存放在數組的哪一個節點下)

2、Java8 HashMap存入的源碼註釋算法

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
        // 判斷當前數組是否已經進行了初始化
        // tab是當前Node數組
        if ((tab = table) == null || (n = tab.length) == 0)
            // 若是沒有初始化,則初始化,擴充數組
            n = (tab = resize()).length;
        // 表示當前index位置沒有存儲位置
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        // 表示索引的坑位被佔用
        else {
            HashMap.Node<K,V> e; K k;
            // 判斷當前的key是否存在,若是存在,則覆蓋
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // 判斷是不是紅黑樹,則往樹裏插入元素
            else if (p instanceof HashMap.TreeNode)
                e = ((HashMap.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);
                        // 若是鏈表長度大於等於8,則將鏈表轉換成紅黑樹
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // 若是有重複元素,則跳出
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            // 替換舊值
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        // 迭代器 failfast 快速失敗
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

3、HashMap的組成數組

在jdk8之前(不包含jdk8),HashMap是由數組與鏈表構成,而在jdk8作了改動,當鏈表的元素大於等於8個時候,則將鏈表改形成紅黑數,目的是爲了追求穩定,不管是增刪查,他的時間複雜度趨於穩定,都是O(logn)app

相關文章
相關標籤/搜索