Java 集合系列10: HashMap深入解析(1)
- 2019 年 10 月 5 日
- 筆記
概要
這一章,我們對HashMap進行學習。 我們先對HashMap有個整體認識,然後再學習它的源碼,最後再通過實例來學會使用HashMap。
第1部分 HashMap介紹
HashMap簡介
HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。 HashMap 繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable介面。 HashMap 的實現不是同步的,這意味著它不是執行緒安全的。它的key、value都可以為null。此外,HashMap中的映射不是有序的。
HashMap 的實例有兩個參數影響其性能:「初始容量」 和 「載入因子」。容量 是哈希表中桶的數量,初始容量 只是哈希表在創建時的容量。載入因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了載入因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。 通常,默認載入因子是 0.75, 這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括 get 和 put 操作,都反映了這一點)。在設置初始容量時應該考慮到映射中所需的條目數及其載入因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以載入因子,則不會發生 rehash 操作。
HashMap的構造函數
HashMap共有4個構造函數,如下:
// 默認構造函數。 HashMap() // 指定「容量大小」的構造函數 HashMap(int capacity) // 指定「容量大小」和「載入因子」的構造函數 HashMap(int capacity, float loadFactor) // 包含「子Map」的構造函數 HashMap(Map<? extends K, ? extends V> map)
HashMap的API
void clear() Object clone() boolean containsKey(Object key) boolean containsValue(Object value) Set<Entry<K, V>> entrySet() V get(Object key) boolean isEmpty() Set<K> keySet() V put(K key, V value) void putAll(Map<? extends K, ? extends V> map) V remove(Object key) int size() Collection<V> values()
第2部分 HashMap數據結構
HashMap的繼承關係
java.lang.Object ↳ java.util.AbstractMap<K, V> ↳ java.util.HashMap<K, V> public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { }
HashMap與Map關係如下圖:

這裡寫圖片描述 從圖中可以看出: (01) HashMap繼承於AbstractMap類,實現了Map介面。Map是"key-value鍵值對"介面,AbstractMap實現了"鍵值對"的通用函數介面。 (02) HashMap是通過"拉鏈法"實現的哈希表。它包括幾個重要的成員變數:table, size, threshold, loadFactor, modCount
。 table
是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。 size
是HashMap的大小,它是HashMap保存的鍵值對的數量。 threshold
是HashMap的閾值,用於判斷是否需要調整HashMap的容量。threshold的值="容量*載入因子",當HashMap中存儲數據的數量達到threshold時,就需要將HashMap的容量加倍。 loadFactor
就是載入因子。 modCount
是用來實現fail-fast機制的。
第3部分 HashMap源碼解析(基於JDK1.6.0_45)
為了更了解HashMap的原理,下面對HashMap源碼程式碼作出分析。 在閱讀源碼時,建議參考後面的說明來建立對HashMap的整體認識,這樣更容易理解HashMap。
package java.util; import java.io.*; public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { // 默認的初始容量是16,必須是2的冪。 static final int DEFAULT_INITIAL_CAPACITY = 16; // 最大容量(必須是2的冪且小於2的30次方,傳入容量過大將被這個值替換) static final int MAXIMUM_CAPACITY = 1 << 30; // 默認載入因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; // 存儲數據的Entry數組,長度是2的冪。 // HashMap是採用拉鏈法實現的,每一個Entry本質上是一個單向鏈表 transient Entry[] table; // HashMap的大小,它是HashMap保存的鍵值對的數量 transient int size; // HashMap的閾值,用於判斷是否需要調整HashMap的容量(threshold = 容量*載入因子) int threshold; // 載入因子實際大小 final float loadFactor; // HashMap被改變的次數 transient volatile int modCount; // 指定「容量大小」和「載入因子」的構造函數 public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); // HashMap的最大容量只能是MAXIMUM_CAPACITY if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // 找出「大於initialCapacity」的最小的2的冪 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; // 設置「載入因子」 this.loadFactor = loadFactor; // 設置「HashMap閾值」,當HashMap中存儲數據的數量達到threshold時,就需要將HashMap的容量加倍。 threshold = (int)(capacity * loadFactor); // 創建Entry數組,用來保存數據 table = new Entry[capacity]; init(); } // 指定「容量大小」的構造函數 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } // 默認構造函數。 public HashMap() { // 設置「載入因子」 this.loadFactor = DEFAULT_LOAD_FACTOR; // 設置「HashMap閾值」,當HashMap中存儲數據的數量達到threshold時,就需要將HashMap的容量加倍。 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); // 創建Entry數組,用來保存數據 table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); } // 包含「子Map」的構造函數 public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); // 將m中的全部元素逐個添加到HashMap中 putAllForCreate(m); } static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } // 返回索引值 // h & (length-1)保證返回值的小於length static int indexFor(int h, int length) { return h & (length-1); } public int size() { return size; } public boolean isEmpty() { return size == 0; } // 獲取key對應的value public V get(Object key) { if (key == null) return getForNullKey(); // 獲取key的hash值 int hash = hash(key.hashCode()); // 在「該hash值對應的鏈表」上查找「鍵值等於key」的元素 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; } // 獲取「key為null」的元素的值 // HashMap將「key為null」的元素存儲在table[0]位置! private V getForNullKey() { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; } // HashMap是否包含key public boolean containsKey(Object key) { return getEntry(key) != null; } // 返回「鍵為key」的鍵值對 final Entry<K,V> getEntry(Object key) { // 獲取哈希值 // HashMap將「key為null」的元素存儲在table[0]位置,「key不為null」的則調用hash()計算哈希值 int hash = (key == null) ? 0 : hash(key.hashCode()); // 在「該hash值對應的鏈表」上查找「鍵值等於key」的元素 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; } // 將「key-value」添加到HashMap中 public V put(K key, V value) { // 若「key為null」,則將該鍵值對添加到table[0]中。 if (key == null) return putForNullKey(value); // 若「key不為null」,則計算該key的哈希值,然後將其添加到該哈希值對應的鏈表中。 int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // 若「該key」對應的鍵值對已經存在,則用新的value取代舊的value。然後退出! if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 若「該key」對應的鍵值對不存在,則將「key-value」添加到table中 modCount++; addEntry(hash, key, value, i); return null; } // putForNullKey()的作用是將「key為null」鍵值對添加到table[0]位置 private V putForNullKey(V value) { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 這裡的完全不會被執行到! modCount++; addEntry(0, null, value, 0); return null; } // 創建HashMap對應的「添加方法」, // 它和put()不同。putForCreate()是內部方法,它被構造函數等調用,用來創建HashMap // 而put()是對外提供的往HashMap中添加元素的方法。 private void putForCreate(K key, V value) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); // 若該HashMap表中存在「鍵值等於key」的元素,則替換該元素的value值 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } // 若該HashMap表中不存在「鍵值等於key」的元素,則將該key-value添加到HashMap中 createEntry(hash, key, value, i); } // 將「m」中的全部元素都添加到HashMap中。 // 該方法被內部的構造HashMap的方法所調用。 private void putAllForCreate(Map<? extends K, ? extends V> m) { // 利用迭代器將元素逐個添加到HashMap中 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); putForCreate(e.getKey(), e.getValue()); } } // 重新調整HashMap的大小,newCapacity是調整後的單位 void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } // 新建一個HashMap,將「舊HashMap」的全部元素添加到「新HashMap」中, // 然後,將「新HashMap」賦值給「舊HashMap」。 Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); } // 將HashMap中的全部元素都添加到newTable中 void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } } // 將"m"的全部元素都添加到HashMap中 public void putAll(Map<? extends K, ? extends V> m) { // 有效性判斷 int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0) return; // 計算容量是否足夠, // 若「當前實際容量 < 需要的容量」,則將容量x2。 if (numKeysToBeAdded > threshold) { int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; while (newCapacity < targetCapacity) newCapacity <<= 1; if (newCapacity > table.length) resize(newCapacity); } // 通過迭代器,將「m」中的元素逐個添加到HashMap中。 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); put(e.getKey(), e.getValue()); } } // 刪除「鍵為key」元素 public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } // 刪除「鍵為key」的元素 final Entry<K,V> removeEntryForKey(Object key) { // 獲取哈希值。若key為null,則哈希值為0;否則調用hash()進行計算 int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; // 刪除鏈表中「鍵為key」的元素 // 本質是「刪除單向鏈表中的節點」 while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; } // 刪除「鍵值對」 final Entry<K,V> removeMapping(Object o) { if (!(o instanceof Map.Entry)) return null; Map.Entry<K,V> entry = (Map.Entry<K,V>) o; Object key = entry.getKey(); int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; // 刪除鏈表中的「鍵值對e」 // 本質是「刪除單向鏈表中的節點」 while (e != null) { Entry<K,V> next = e.next; if (e.hash == hash && e.equals(entry)) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; } // 清空HashMap,將所有的元素設為null public void clear() { modCount++; Entry[] tab = table; for (int i = 0; i < tab.length; i++) tab[i] = null; size = 0; } // 是否包含「值為value」的元素 public boolean containsValue(Object value) { // 若「value為null」,則調用containsNullValue()查找 if (value == null) return containsNullValue(); // 若「value不為null」,則查找HashMap中是否有值為value的節點。 Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value)) return true; return false; } // 是否包含null值 private boolean containsNullValue() { Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value == null) return true; return false; } // 克隆一個HashMap,並返回Object對象 public Object clone() { HashMap<K,V> result = null; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // assert false; } result.table = new Entry[table.length]; result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); // 調用putAllForCreate()將全部元素添加到HashMap中 result.putAllForCreate(this); return result; } // Entry是單向鏈表。 // 它是 「HashMap鏈式存儲法」對應的鏈表。 // 它實現了Map.Entry 介面,即實現getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函數 static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; // 指向下一個節點 Entry<K,V> next; final int hash; // 構造函數。 // 輸入參數包括"哈希值(h)", "鍵(k)", "值(v)", "下一節點(n)" Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } public final K getKey() { return key; } public final V getValue() { return value; } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } // 判斷兩個Entry是否相等 // 若兩個Entry的「key」和「value」都相等,則返回true。 // 否則,返回false public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } // 實現hashCode() public final int hashCode() { return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } public final String toString() { return getKey() + "=" + getValue(); } // 當向HashMap中添加元素時,繪調用recordAccess()。 // 這裡不做任何處理 void recordAccess(HashMap<K,V> m) { } // 當從HashMap中刪除元素時,繪調用recordRemoval()。 // 這裡不做任何處理 void recordRemoval(HashMap<K,V> m) { } } // 新增Entry。將「key-value」插入指定位置,bucketIndex是位置索引。 void addEntry(int hash, K key, V value, int bucketIndex) { // 保存「bucketIndex」位置的值到「e」中 Entry<K,V> e = table[bucketIndex]; // 設置「bucketIndex」位置的元素為「新Entry」, // 設置「e」為「新Entry的下一個節點」 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); // 若HashMap的實際大小 不小於 「閾值」,則調整HashMap的大小 if (size++ >= threshold) resize(2 * table.length); } // 創建Entry。將「key-value」插入指定位置,bucketIndex是位置索引。 // 它和addEntry的區別是: // (01) addEntry()一般用在 新增Entry可能導致「HashMap的實際容量」超過「閾值」的情況下。 // 例如,我們新建一個HashMap,然後不斷通過put()向HashMap中添加元素; // put()是通過addEntry()新增Entry的。 // 在這種情況下,我們不知道何時「HashMap的實際容量」會超過「閾值」; // 因此,需要調用addEntry() // (02) createEntry() 一般用在 新增Entry不會導致「HashMap的實際容量」超過「閾值」的情況下。 // 例如,我們調用HashMap「帶有Map」的構造函數,它繪將Map的全部元素添加到HashMap中; // 但在添加之前,我們已經計算好「HashMap的容量和閾值」。也就是,可以確定「即使將Map中 // 的全部元素添加到HashMap中,都不會超過HashMap的閾值」。 // 此時,調用createEntry()即可。 void createEntry(int hash, K key, V value, int bucketIndex) { // 保存「bucketIndex」位置的值到「e」中 Entry<K,V> e = table[bucketIndex]; // 設置「bucketIndex」位置的元素為「新Entry」, // 設置「e」為「新Entry的下一個節點」 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); size++; } // HashIterator是HashMap迭代器的抽象出來的父類,實現了公共了函數。 // 它包含「key迭代器(KeyIterator)」、「Value迭代器(ValueIterator)」和「Entry迭代器(EntryIterator)」3個子類。 private abstract class HashIterator<E> implements Iterator<E> { // 下一個元素 Entry<K,V> next; // expectedModCount用於實現fast-fail機制。 int expectedModCount; // 當前索引 int index; // 當前元素 Entry<K,V> current; HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] t = table; // 將next指向table中第一個不為null的元素。 // 這裡利用了index的初始值為0,從0開始依次向後遍歷,直到找到不為null的元素就退出循環。 while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } // 獲取下一個元素 final Entry<K,V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); // 注意!!! // 一個Entry就是一個單向鏈表 // 若該Entry的下一個節點不為空,就將next指向下一個節點; // 否則,將next指向下一個鏈表(也是下一個Entry)的不為null的節點。 if ((next = e.next) == null) { Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e; return e; } // 刪除當前元素 public void remove() { if (current == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Object k = current.key; current = null; HashMap.this.removeEntryForKey(k); expectedModCount = modCount; } } // value的迭代器 private final class ValueIterator extends HashIterator<V> { public V next() { return nextEntry().value; } } // key的迭代器 private final class KeyIterator extends HashIterator<K> { public K next() { return nextEntry().getKey(); } } // Entry的迭代器 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } // 返回一個「key迭代器」 Iterator<K> newKeyIterator() { return new KeyIterator(); } // 返回一個「value迭代器」 Iterator<V> newValueIterator() { return new ValueIterator(); } // 返回一個「entry迭代器」 Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); } // HashMap的Entry對應的集合 private transient Set<Map.Entry<K,V>> entrySet = null; // 返回「key的集合」,實際上返回一個「KeySet對象」 public Set<K> keySet() { Set<K> ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } // Key對應的集合 // KeySet繼承於AbstractSet,說明該集合中沒有重複的Key。 private final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return newKeyIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return HashMap.this.removeEntryForKey(o) != null; } public void clear() { HashMap.this.clear(); } } // 返回「value集合」,實際上返回的是一個Values對象 public Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); } // 「value集合」 // Values繼承於AbstractCollection,不同於「KeySet繼承於AbstractSet」, // Values中的元素能夠重複。因為不同的key可以指向相同的value。 private final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return newValueIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsValue(o); } public void clear() { HashMap.this.clear(); } } // 返回「HashMap的Entry集合」 public Set<Map.Entry<K,V>> entrySet() { return entrySet0(); } // 返回「HashMap的Entry集合」,它實際是返回一個EntrySet對象 private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } // EntrySet對應的集合 // EntrySet繼承於AbstractSet,說明該集合中沒有重複的EntrySet。 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> e = (Map.Entry<K,V>) o; Entry<K,V> candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } public boolean remove(Object o) { return removeMapping(o) != null; } public int size() { return size; } public void clear() { HashMap.this.clear(); } } // java.io.Serializable的寫入函數 // 將HashMap的「總的容量,實際容量,所有的Entry」都寫入到輸出流中 private void writeObject(java.io.ObjectOutputStream s) throws IOException { Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null; // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); // Write out number of buckets s.writeInt(table.length); // Write out size (number of Mappings) s.writeInt(size); // Write out keys and values (alternating) if (i != null) { while (i.hasNext()) { Map.Entry<K,V> e = i.next(); s.writeObject(e.getKey()); s.writeObject(e.getValue()); } } } private static final long serialVersionUID = 362498820763181265L; // java.io.Serializable的讀取函數:根據寫入方式讀出 // 將HashMap的「總的容量,實際容量,所有的Entry」依次讀出 private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the threshold, loadfactor, and any hidden stuff s.defaultReadObject(); // Read in number of buckets and allocate the bucket array; int numBuckets = s.readInt(); table = new Entry[numBuckets]; init(); // Give subclass a chance to do its thing. // Read in size (number of Mappings) int size = s.readInt(); // Read the keys and values, and put the mappings in the HashMap for (int i=0; i<size; i++) { K key = (K) s.readObject(); V value = (V) s.readObject(); putForCreate(key, value); } } // 返回「HashMap總的容量」 int capacity() { return table.length; } // 返回「HashMap的載入因子」 float loadFactor() { return loadFactor; } }
說明:
在詳細介紹HashMap的程式碼之前,我們需要了解:HashMap就是一個散列表,它是通過「拉鏈法」解決哈希衝突的。 還需要再補充說明的一點是影響HashMap性能的有兩個參數:初始容量(initialCapacity) 和載入因子(loadFactor)。容量 是哈希表中桶的數量,初始容量只是哈希表在創建時的容量。載入因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了載入因子與當前容量的乘積時,則要對該哈希表進行 rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。