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,以免調整大小和樹化閾值之間的衝突。
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; } }
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
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;//不是比價器子類 }
@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)); }
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;//哈希表的加載因子
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // 全部其餘屬性都是默認的(DEFAULT_LOAD_FACTOR = 0.75f) }
public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR);//(DEFAULT_LOAD_FACTOR = 0.75f) }
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的冪 }
public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR;//默認的負載因子 putMapEntries(m, false); }
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); } } }
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; }
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; }