HashMap源碼解析(一)

常量

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //默認初始容量 (必須是2的冪,用左移動)

  
    static final int MAXIMUM_CAPACITY = 1 << 30;//最大容量,若是隱式指定更高的值,則使用該容量(必須是2的冪且小於等於1 << 30)

   
    static final float DEFAULT_LOAD_FACTOR = 0.75f;//加載因子(負載係數)(用來衡量HashMap滿的程度)(默認0.75f)

   
    static final int TREEIFY_THRESHOLD = 8;//(鏈表轉樹的閾值)

    
    static final int UNTREEIFY_THRESHOLD = 6;//(樹轉鏈表的閾值)

 
    static final int MIN_TREEIFY_CAPACITY = 64;//容器能夠樹化的最小容量。 (不然,若是bin中的節點太多,則會調整表的大小。)應該至少爲4 * TREEIFY_THRESHOLD,以免調整大小和樹化閾值之間的衝突。

基本哈希bin節點Node

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;//哈希值
        final K key;//存儲鍵
        V value;//存儲值
        Node<K,V> next;//下一個節點

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }//返回鍵值
        public final V getValue()      { return value; }//返回存儲值
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);//鍵值的hash與上存儲值的hash,Objects.hashCode()入參爲null返回0
        }

        public final V setValue(V newValue) {//設置值並返回舊值
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)//內存地址相同直接返回true
                return true;
            if (o instanceof Map.Entry) {//若是是Entry 的子類
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue()))//調用當前節點key值的equal方法和當前節點value值的equal方法,結果與
                    return true;
            }
            return false;
        }
    }

靜態工具類(方法)

hash(Object key)

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//key的hash值和key的hash值的高16位作異或(>>>左邊高位補0)(任何數跟0異或都是其自己)(因此結果是:也就是高十六位+高十六位^低十六位)
    }

範例數組

hash(-10)

-10.hashCode:       1111111111111111_1111111111110110
-10.hashCode>>>16:  0000000000000000_1111111111111111 
return:             1111111111111111_0000000000001001

comparableClassFor 若是它的形式爲「class C implements Comparable <C>」,則返回x的Class,不然返回null

static Class<?> comparableClassFor(Object x) {
        if (x instanceof Comparable) {//若是是比較器子類
            Class<?> c; Type[] ts, as; ParameterizedType p;
            if ((c = x.getClass()) == String.class) // bypass checks
                return c;//若是是String返回String類
            if ((ts = c.getGenericInterfaces()) != null) {//若是實現了接口
                for (Type t : ts) {//循環實現的接口
                    if (
                        (t instanceof ParameterizedType) &&
                        ((p = (ParameterizedType) t).getRawType() == Comparable.class) &&
                        (as = p.getActualTypeArguments()) != null &&
                        as.length == 1 && 
                        as[0] == c
                        ) // type arg is c
                        return c;
                }
            }
        }
        return null;//不是比價器子類
    }

compareComparables() 若是x匹配kc(k的篩選可比類),則返回k.compareTo(x),不然返回0。

@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
    static int compareComparables(Class<?> kc, Object k, Object x) {
        return (x == null || x.getClass() != kc ? 0 :
                ((Comparable)k).compareTo(x));
    }

tableSizeFor 返回給定目標容量的兩個大小的冪(返回能裝下傳入參數的大小,且爲2的次方)

static final int tableSizeFor(int cap) {
        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);//Integer.numberOfLeadingZeros返回左邊開會連續的0個數
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

Integer.numberOfLeadingZeros()返回左邊最高位開始0的個數緩存

計算範例 tableSizeFor(5)函數

n = -1 >>> Integer.numberOfLeadingZeros(5-1)

-1:              11111111_11111111_11111111_11111111
5-1=4:          00000000_00000000_00000000_00000100
Integer.numberOfLeadingZeros(5-1):29
-1>>>29:         00000000_00000000_00000000_00000111

n=7
n>0
n<MAXIMUM_CAPACITY
return: n+1
return: 7+1
return: 8

變量

transient Node<K,V>[] table;//哈希桶數組(該表在首次使用時初始化)

    
    transient Set<Map.Entry<K,V>> entrySet;//保持緩存的entrySet()  AbstractMap字段用於keySet()和values()
    
    
    transient int size;//此映射中包含的鍵 - 值映射的數量

    transient int modCount;//此HashMap已被結構修改的次數

   
    int threshold;//下一次須要擴容時的大小(capacity * load factor)(初值爲0)

   
    final float loadFactor;//哈希表的加載因子

構造方法

HashMap()(默認的負載因子是0.75f)

public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // 全部其餘屬性都是默認的(DEFAULT_LOAD_FACTOR = 0.75f)
    }

HashMap(int initialCapacity)(自定義容量)(經過tableSizeFor來計算2的次方的容量大小)

public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);//(DEFAULT_LOAD_FACTOR = 0.75f)
    }

HashMap(int initialCapacity, float loadFactor)

public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)//容量小於0,拋出異常
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)//容量大於最大容量1 << 30
            initialCapacity = MAXIMUM_CAPACITY;//則使用最大容量
        if (loadFactor <= 0 || Float.isNaN(loadFactor))//若是負載因子小於0或者不是數字,拋出異常
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;//賦值負載因子
        this.threshold = tableSizeFor(initialCapacity);//計算容量,爲2的冪
    }

HashMap(Map<? extends K, ? extends V> m)根據一個map構造一個map

public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;//默認的負載因子
        putMapEntries(m, false);
    }

 putMapEntries(Map<? extends K, ? extends V> m, boolean evict)實現Map.putAll和Map構造函數

final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();//獲取m映射數量
        if (s > 0) {//長度大於0
        
            if (table == null) { //表是空的(沒有數據)
                float ft = ((float)s / loadFactor) + 1.0F;//按照默認負載因子比例計算出的大小+1
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);//小於最大容量就使用ft計算,大於最大容量使用最大容量計算
                if (t > threshold)//若是超過擴容閾值,那麼就從新計算擴容閾值
                    threshold = tableSizeFor(t);//從新計算擴容閾值(2的冪)
            }
            else if (s > threshold)//若是表不是空的,且大小大於擴容閾值
                resize();//進行擴容
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {//循環插入
                K key = e.getKey();//獲取key
                V value = e.getValue();//獲取value
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

resize()擴容

final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;//舊的表
        int oldCap = (oldTab == null) ? 0 : oldTab.length;//不爲空的話賦值爲舊錶數據量
        int oldThr = threshold;//獲取擴容的閾值
        int newCap, newThr = 0;
        
        
        if (oldCap > 0) {//若是舊錶不爲空
        
        
            if (oldCap >= MAXIMUM_CAPACITY) {//若是舊錶數據量大於最大容量
                threshold = Integer.MAX_VALUE;//擴容閾值設置成0x7fffffff(1111111111111111111111111111111)
                return oldTab;//返回舊的數據表
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY&&oldCap >= DEFAULT_INITIAL_CAPACITY)//不然,兩倍大小小於最大容量,且舊的空間大於初始化空間
                newThr = oldThr << 1; // 新的閾值爲舊的閾值兩倍
        }
        
        
        else if (oldThr > 0) //舊錶爲空,且舊錶閾值>0 
            newCap = oldThr;//初始容量被置於閾值
        else {   //舊錶爲空,且舊錶閾值<0           
            newCap = DEFAULT_INITIAL_CAPACITY;//默認的空間
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);//默認的閾值
        }//if (oldCap > 0)結束
        
        
        if (newThr == 0) {//若是新的閾值等於0
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        
        threshold = newThr;//從新賦值閾值
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {//有舊的數據
        
            for (int j = 0; j < oldCap; ++j) {// 把每一個哈希桶裏的值都移動到新的哈希桶中
            
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {//哈希桶位不爲空
                
                    oldTab[j] = null;//原位置空
                    if (e.next == null)//若是這個桶位只有這一個元素(沒有next)
                        newTab[e.hash & (newCap - 1)] = e;//用新的長度取模,數據放置位置
                    else if (e instanceof TreeNode)//若是是紅黑樹
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { //若是是鏈表
                    
                        Node<K,V> loHead = null, loTail = null;//低位頭尾
                        Node<K,V> hiHead = null, hiTail = null;//高位頭尾
                        Node<K,V> next;
                        
                        do {
                        
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                            
                        } while ((e = next) != null);//循環直至鏈表沒有下一個節點
                        
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                        
                    }//(e.next == null)的else結尾
                    
                }//if ((e = oldTab[j]) != null)結尾
                
            }// for (int j = 0; j < oldCap; ++j)結尾
            
            
        }//if (oldTab != null)結尾
        
        return newTab;
    }

putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) 放置值

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)//若是桶是空的,或者桶的長度是0
            n = (tab = resize()).length;//擴容
        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 &&
                ((k = p.key) == key || (key != null && key.equals(k))))//和鏈表的第一個值同值,進行覆蓋
                e = p;
            else if (p instanceof TreeNode)//紅黑樹
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {//binCount爲下標指針循環鏈表
                    if ((e = p.next) == null) {//循環到鏈表的末尾(next爲空)
                        p.next = newNode(hash, key, value, null);//把插入的節點做爲鏈表的末尾的下一個節點
                        if (binCount >= TREEIFY_THRESHOLD - 1) //若是達到樹化的閾值,那麼轉化爲樹
                            treeifyBin(tab, hash);
                        break;//結束循環
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))//插入的節點和鏈表某一個節點相同,直接跳出
                        break;
                    p = e;//循環指針p移到下一位
                }
            }
            if (e != null) { //已存在映射,覆蓋
                V oldValue = e.value;//獲取舊值
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;//賦值
                afterNodeAccess(e);//後期回調操做
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)//是否達到擴容閾值
            resize();
        afterNodeInsertion(evict);//後期回調操做
        return null;
    }
相關文章
相關標籤/搜索