public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
複製代碼
HashMap綜合了ArrayList和LinkList的優勢
java
/**
* 默認初始容量16,必須是2的冪
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
/**
* 最大容量
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默認負載因子。當鍵值對的數量大於 CAPACITY * 0.75 時,就會觸發擴容
* 如無參的HashMap構造器,初始化容量爲16,當鍵值對的數量大於 16 * 0.75 = 12時,就會觸發擴容
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 計數閾值。鏈表的元素大於8的時候,鏈表將轉化爲樹
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 計數閾值。resize操做時,紅黑樹的節點數量小於6時使用鏈表來代替樹
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 在轉變成樹以前,還會有一次判斷,只有鍵值對數量大於 64 纔會發生轉換。
* 這是爲了不在哈希表創建初期,多個鍵值對剛好被放入了同一個鏈表中而致使沒必要要的轉化
*/
static final int MIN_TREEIFY_CAPACITY = 64;
複製代碼
/**
* 存儲數據的哈希表,默認容量16。長度老是2的冪
*/
transient Node<K,V>[] table;
/**
* Entry集合,主要用於迭代功能
*/
transient Set<Map.Entry<K,V>> entrySet;
/**
* 實際存在的Node數量,不必定等於table的長度(初始化容量),甚至可能大於它。
*/
transient int size;
/**
* HashMap結構被修改的次數,迭代過程當中遵循Fail-Fast機制。
* 保證多線程同時修改map時,能及時的發現(操做前備份的count和當前modCount不相等)並拋出異常終止操做。
*/
transient int modCount;
/**
* 擴容閾值,超過(capacity * loadFactor)時,自動擴容容量爲原來的二倍。
*/
int threshold;
/**
* 負載因子,可計算threshold:threshold = capacity * loadFactor
*/
final float loadFactor;
複製代碼
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
複製代碼
主要談談HashMap(int initialCapacity, float loadFactor);實例化時,內部調用tableSizeFor(initialCapacity)初始化容量;方法以下數組
/**
* 根據整數cap求解大於等於它,且爲2的整數次冪的最小值
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
複製代碼
對於求解大於等於它,且爲2的整數次冪的最小值,int n = cap - 1;很關鍵。 假設不執行int n = cap - 1;cap = 8。按照java8的設計思想,由於8>=2^3,結果就應該是8,但結果倒是16.bash
8的二進制:1000
n |= n >>> 1; n = n | n >>> 1; 1000 | 0100 = 1100
n |= n >>> 2; n = n | n >>> 2; 1100 | 0011 = 1111
n |= n >>> 4; n = n | n >>> 4; 1111 | 0000 = 1111
...
n |= n >>> 16; n = 1111 = 15(十進制),最後執行n + 1 = 16
複製代碼