1. 程式人生 > 實用技巧 >HashMap原始碼分析(一)

HashMap原始碼分析(一)

原理簡介:
HashMap是利用雜湊表原理來儲存元素的一種集合。在JDK1.7中,HashMap底層是 陣列+連結串列 的, 在JDK1.8以後,HashMap底層改為 陣列+連結串列+紅黑樹 構成, 效率也變的更高效。

HashMap原始碼主要從幾個方面來看.

一 定義
  public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable   

  繼承AbstractMap 實現Map介面, Cloneable介面 ,能複製和序列化.


二 成員變數 (原理中必須要用到的幾個重要引數)
  private static final long serialVersionUID = 362498820763181265L;         // UID 序列化用的.不解釋
  static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;                       // aka 16, 初始化的陣列容量, 預設是16. 必須是2的倍數.
  static final int MAXIMUM_CAPACITY = 1 << 30;                              // 集合最大容量,1 << 30 為2的30次冪. 10億多.
  static final float DEFAULT_LOAD_FACTOR = 0.75f;                           // 擴充套件因子, 0.75, 當陣列中元素數量超過總容量的0.75倍(如預設容量16的0.75倍 12時,就會自動擴容)
  static final int TREEIFY_THRESHOLD = 8;                          // 樹化閾值(JDK1.8新增), 8 ,也就是當連結串列中元素個數大於等於8時, 連結串列會轉化為紅黑樹.對照下面的樹退化閾值記憶.
  static final int UNTREEIFY_THRESHOLD = 6;                                 // 樹退化閾值(JDK1.8新增), 6, 當紅黑樹中元素個數少於等於6時, 紅黑樹會轉化為連結串列. 呼應前面的樹化閾值.
  static final int MIN_TREEIFY_CAPACITY = 64;                   // 當map中鍵值對總數量大於64時, 才會去判斷上面的樹化閾值.小於64時, 桶內元素太多隻會擴容,不會化成樹.
                                              //為了避免擴容和樹形化選擇衝突,這個值不能低於4*TREEIFY_THRESHOLD ,即32.

  

三  桶結構原始碼(從原始碼中可以看出,hash方式為key和value分別雜湊,結果再異或)
    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);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }