HashMap<String, String> map = new HashMap<>(); public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); }
空的構造方法默認調用有參構造數組
DEFAULT_INITIAL_CAPACITY 默認大小 16 DEFAULT_LOAD_FACTOR 默認加載因子 0.75
public HashMap(int initialCapacity, float loadFactor) { //作參數校驗 加載因子 容量大小 (大於0 小於等於MAXIMUM_CAPACITY) this.loadFactor = loadFactor; threshold = initialCapacity; init(); }
map.put("k1", "v1"); //put方法 public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
inflateTable
方法/** * Inflates the table. */ private void inflateTable(int toSize) { // Find a power of 2 >= toSize //該方法用於尋找一個大於或等於該數的一個2的冪次方數, //爲後期擴容或計算元素存放位置 int capacity = roundUpToPowerOf2(toSize); threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; initHashSeedAsNeeded(capacity); }
roundUpToPowerOf2
方法private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; int rounded = number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (rounded = Integer.highestOneBit(number)) != 0 ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded : 1; return rounded; } /** * 該方法用於返回一個小於等於i的一個2的冪次方數 * 採用的的方法爲最高爲 1 */ public static int highestOneBit(int i) { // HD, Figure 3-1 i |= (i >> 1); i |= (i >> 2); i |= (i >> 4); i |= (i >> 8); i |= (i >> 16); //這裏i得出爲 00....0 1111 //i >>> 1 00....0 0111 //減去獲得 00....0 1000 return i - (i >>> 1); }
該方法就是講hash值與對應的Entry數組的長度進行與運算 static int indexFor(int h, int length) { // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2"; return h & (length-1); }
final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). //爲了讓數組元素存放的更加散列讓高位也參與運算 h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
addEntry
方法void addEntry(int hash, K key, V value, int bucketIndex) { //當存放元素個數超過容量*加載因子 且當前下標爲 bucketIndex的table已經存放過元素則擴容 if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); }
createEntry()
方法void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; //這裏完成的邏輯就是將 新的Entry對象 的next指向table[bucketIndex] 當前存放的元素, 而後將table[bucketIndex] 指向新的Entry對象 table[bucketIndex] = new Entry<>(hash, key, value, e); size++; }
resize()
方法// newCapacity爲以前數組元素長度的兩倍 void resize(int newCapacity) { //轉移元素到新數組 transfer(newTable, initHashSeedAsNeeded(newCapacity)); }
/** * Initialize the hashing mask value. We defer initialization until we * really need it. */ //該方法就是爲了從新生成hahs種子 final boolean initHashSeedAsNeeded(int capacity) { //這裏hashSeed以前默認爲0 因此爲false boolean currentAltHashing = hashSeed != 0; boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); //因此這裏只有當useAltHashing返回true //纔會從新計算hashSeed boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0; } return switching; }
transfer
方法void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; //遍歷當前Entry數組以及鏈表 即遍歷全部元素 //這裏在併發環境下,會出現循環列表的狀況 //因此在get或put的時候就可能會致使死循環 for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }