package java.util; import java.io.*; public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { /** * 默認的初始容量,必須是2的冪 */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * MUST be a power of two <= 1<<30. * 最大容量,若是構造方法沒有設置參數將指定一個較高值 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 默認裝載因子。 * 默認的entry數組的長度爲16。裝載因子的意義在於使得entry數組有冗餘, * 默認即容許25%的冗餘,當HashMap的數據的個數超過12(16*0.75)時 * 即會對entry數組進行第一次擴容,後面的再次擴容依次類推。 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 存儲實體的數組,可調整。數據長度老是2的冪 * transient 序列化時忽略該字段。數組存放的是實體的引用,序列化時必須遍歷該字段逐個實體序列化。 */ transient Entry[] table; /** * 鍵值對的數目 * transient 序列化時忽略該字段。反序列化的時候讀取出每對key、value值,再存入HashMap的數組中 */ transient int size; /** * 下一個容量調整值(擴容臨界值) */ int threshold; /** * 裝載因子 * @serial */ final float loadFactor; /** * map結構被改變的次數 * 結構上的修改是指更改在HashMap中映射的數量或以其餘方式修改它的內部結構(例如,刷新) * 該字段在HashMap使用迭代器遍歷的時候使用 */ transient volatile int modCount; /** * 根據初始容量和加載因子建立一個空的HashMap * (初始容量小於0或裝載因子小於等於0將報異常) */ public HashMap(int initialCapacity, float loadFactor) { // 初始容量小於0,拋出非法參數異常 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); // 初始容量大於最大容量,調整初始容量 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; // 加載因子小於等於0或者非浮點數,拋出非法參數異常 if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity // 設置capacity爲大於initialCapacity且是2的冪的最小值 int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; //設置加載因子 this.loadFactor = loadFactor; //設置擴容臨界值 threshold = (int)(capacity * loadFactor); //建立數組 table = new Entry[capacity]; //初始化 init(); } /** * 根據指定容量建立一個空的HashMap */ public HashMap(int initialCapacity) { // 調用上面的構造方法,容量爲指定的容量,裝載因子是默認值 this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * 根據默認初始化容量和默認加載因子(0.75)建立HashMap */ public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); } /** * 經過傳入的map建立一個HashMap,容量爲默認容量(16)和(map.zise()/DEFAULT_LOAD_FACTORY)+1 * 的較大者,裝載因子爲默認值 */ public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAllForCreate(m); } // internal utilities /** * 初始化方法(鉤子方法) * 全部的構造方法和僞構造方法(clone,readObject)將在HashMap初始化完成以後,元素插入以前調用該方法 */ void init() { } /** * 適用補充hash函數,防止質量較差的hash函數。 * 該方法主要做用是防止質量較差的哈希函數帶來過多的衝突(碰撞)問題。 * Java中int值佔4個字節,即32位。根據這32位值進行移位、異或運算獲得一個值。 */ static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } /** * 返回Hash code h的值在存儲數組中的索引 * 爲啥和length-1進行與運算,由於這樣能夠保證結果的最大值是length-1,不會產生數組越界問題。 */ static int indexFor(int h, int length) { return h & (length-1); } /** * 鍵存儲值對的數量 */ public int size() { return size; } /** * 判斷map是否爲空 */ public boolean isEmpty() { return size == 0; } /** * 根據key查詢value * * @see #put(Object, Object) */ public V get(Object key) { //key爲空 if (key == null) return getForNullKey(); //計算key哈希 int hash = hash(key.hashCode()); //遍歷鏈表 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時的值 */ private V getForNullKey() { //遍歷索引爲零的鏈表,key爲null時映射的索引位置爲0 for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; } /** * 是否包含key */ public boolean containsKey(Object key) { return getEntry(key) != null; } /** * 根據key獲取對應的值,沒有則返回空 */ final Entry<K,V> getEntry(Object key) { //計算哈希值 int hash = (key == null) ? 0 : hash(key.hashCode()); //遍歷鏈表,查詢對應的值 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; } /** * 將指定的值映射指定的鍵。若是指定的鍵已存在映射關係,則舊值會被替換。 */ public V put(K key, V value) { //若是key爲空,則調用putForNullKey方法 if (key == null) return putForNullKey(value); //調用補充hash方法(防止低質量hash方法形成衝突過多問題) int hash = hash(key.hashCode()); //獲取hash code對應的存儲數組索引 int i = indexFor(hash, table.length); //遍歷目標存儲數組單元下的鏈表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //若是已存在鍵值對值的hash等於將要插入兼職對值的hash,而且已存在鍵值對鍵等於將要插入鍵值對鍵 //(內存地址相等或者equals) //即同鍵值覆蓋 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); //返回舊值 return oldValue; } } //修改記錄Map改變次數的值 modCount++; //添加鍵值對 addEntry(hash, key, value, i); return null; } /** * 空鍵插入(私有方法) */ private V putForNullKey(V value) { //先遍歷數組,若是存在key爲空的,先替換值並返回舊值 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; } /** * 該方法被構造函數和僞構造函數(clone,readObject)用來替代put方法。 * 該方法不擴展數組,不檢查map修改次數,方法體調用createEntry方法而非addEntry * */ private void putForCreate(K key, V value) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); /** * Look for preexisting entry for key. This will never happen for * clone or deserialize. It will only happen for construction if the * input Map is a sorted map whose ordering is inconsistent w/ equals. * * 遍歷已存在的鍵,若是和當前key相等,則值替換後返回 */ 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; } } // 沒有則建立 createEntry(hash, key, value, i); } /** * 將指定map中數據插入到當前map中 */ private void putAllForCreate(Map<? extends K, ? extends V> m) { 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()); } } /** * 將當前數據複製到容量更大的數組中。 * 該方法在存儲數量達到臨界值時自動被調用 * * 若是當前容量已達到最大值,該方法不在調整map容量大小,但會設置擴容臨界值爲Integer.MAX_VALUE。 * 這具備防止未來調用的效果 */ void resize(int newCapacity) { // 若是舊數組到達最大值,設置擴容臨界值爲Integer.MAX_VALUE Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //建立指定容量的新數組存儲舊數據 Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; //從新設置擴容臨界值 threshold = (int)(newCapacity * loadFactor); } /** * Transfers all entries from current table to newTable. * 將全部數據從當前數組複製到新數組 * * HashMap之因此不能保持元素的順序有如下幾點緣由: * 第一,插入元素的時候對元素進行哈希處理,不一樣元素分配到table的不一樣位置; * 第二,容量拓展的時候又進行了hash處理; * 第三,複製原表內容的時候鏈表被倒置。 */ void transfer(Entry[] newTable) { //保留原數組引用 Entry[] src = table; //新的容量 int newCapacity = newTable.length; //遍歷源數組 for (int j = 0; j < src.length; j++) { //獲取元素e Entry<K,V> e = src[j]; if (e != null) { // 將原數組中的元素置爲null src[j] = null; do { //循環鏈表 Entry<K,V> next = e.next; // 根據新的容量計算e在新數組中的索引 int i = indexFor(e.hash, newCapacity); // 將e插入到newTable[i]指向的鏈表的頭部 e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } } /** * * 複製全部指定map的映射到當前的map。 * 重複的映射會被替換。(即當前map中的key和指定參數map的key相同,值會被替換) */ public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0) return; /* * 爲何判斷條件是numKeysToBeAdded, * 不是(numKeysToBeAdded+table.length)>threshold? * * 這是一種保守的作法,明顯地,咱們應該在(numKeysToBeAdded+table.length)>threshold * 的時候去拓展容量,可是考慮到將被添加的元素可能會有Key與本來存在的Key相同的狀況, * 因此採用保守的作法,避免拓展到過大的容量。 */ if (numKeysToBeAdded > threshold) { //計算目標容量 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); //目標容量超過最大值, targetCapacity = MAXIMUM_CAPACITY; if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; //獲取大於目標容量最小的2的冥,這就是信容量 int newCapacity = table.length; while (newCapacity < targetCapacity) newCapacity <<= 1; //新容量大於當前數組長度,則擴容 if (newCapacity > table.length) resize(newCapacity); } //遍歷m中的數據,插入到當前的map中 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哈希 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; //遍歷鏈表,並刪除 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; } /** * Special version of remove for EntrySet. */ 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; 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; } /** * * 清空map */ public void clear() { modCount++; Entry[] tab = table; //清空數組 for (int i = 0; i < tab.length; i++) tab[i] = null; size = 0; } /** * * 是否包含指定值 * */ public boolean containsValue(Object value) { //value爲空 if (value == null) return containsNullValue(); //遍歷數組和鏈表(雙重循環,較耗時) 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的value */ 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; } /** * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and * values themselves are not cloned. * * 克隆(只複製引用) * */ public Object clone() { HashMap<K,V> result = null; try { //建立一個空的Map 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(); //將當前的鍵值對插入到新的Map result.putAllForCreate(this); return result; } static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; //對下一個節點的引用 Entry<K,V> next; final int hash; /** * Creates new entry. */ 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; //返回是舊的Value return oldValue; } 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(); // Key相等且Value相等則兩個Entry相等 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是Key的hashCode和Value的hashCode的異或的結果 public final int hashCode() { return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } // 覆寫toString方法,方便調試和查看輸出 public final String toString() { return getKey() + "=" + getValue(); } /** * 當調用put(k,v)方法存入鍵值對時,若是k已經存在,則該方法被調用。 * (沒有函數體、default做用域,why?) */ void recordAccess(HashMap<K,V> m) { } /** * 當Entry被從HashMap中移除時被調用。 * (沒有函數體、default做用域,why?) */ void recordRemoval(HashMap<K,V> m) { } } /** * * 根據指定的鍵,值和哈希碼添加新條目到指定的容器 * */ void addEntry(int hash, K key, V value, int bucketIndex) { //獲取鏈表頭結點 Entry<K,V> e = table[bucketIndex]; //在鏈表頭插入新節點,next指向原來的頭結點 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //若是size達到擴容臨界值,則擴容 if (size++ >= threshold) resize(2 * table.length); } /** * Like addEntry except that this version is used when creating entries * as part of Map construction or "pseudo-construction" (cloning, * deserialization). This version needn't worry about resizing the table. * * Subclass overrides this to alter the behavior of HashMap(Map), * clone, and readObject. */ void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e); size++; } private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return int expectedModCount; // For fast-fail int index; // current slot Entry<K,V> current; // current entry HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry //設置next指向數組第一項 Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } final Entry<K,V> nextEntry() { //迭代過程當中map被修改,拋出異常 if (modCount != expectedModCount) throw new ConcurrentModificationException(); //獲取下一項引用 Entry<K,V> e = next; //爲空,拋出異常 if (e == null) throw new NoSuchElementException(); //(next引用指向下一項的下一項)若是下一項爲鏈表的最後一項,則執行if裏面代碼(next指向數組的下一個非空索引) 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; } } private final class ValueIterator extends HashIterator<V> { public V next() { return nextEntry().value; } } private final class KeyIterator extends HashIterator<K> { public K next() { return nextEntry().getKey(); } } private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } // Subclass overrides these to alter behavior of views' iterator() method Iterator<K> newKeyIterator() { return new KeyIterator(); } Iterator<V> newValueIterator() { return new ValueIterator(); } Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); } // Views private transient Set<Map.Entry<K,V>> entrySet = null; /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> * operations. */ public Set<K> keySet() { Set<K> ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } 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(); } } /** * Returns a {@link Collection} view of the values contained in this map. * The collection is backed by the map, so changes to the map are * reflected in the collection, and vice-versa. If the map is * modified while an iteration over the collection is in progress * (except through the iterator's own <tt>remove</tt> operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding * mapping from the map, via the <tt>Iterator.remove</tt>, * <tt>Collection.remove</tt>, <tt>removeAll</tt>, * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not * support the <tt>add</tt> or <tt>addAll</tt> operations. */ public Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); } 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(); } } /** * * 獲取鍵值對value集合 * * @return a set view of the mappings contained in this map */ public Set<Map.Entry<K,V>> entrySet() { return entrySet0(); } /** * 獲取鍵值對value集合(得到一個代理類) */ private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } /** * 代理類(沒有定義本身的數據,經過迭代器直接遍歷map中的數組鏈表) */ private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { //該代理經過迭代器遍歷map數據,自己不存儲數據 return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> e = (Map.Entry<K,V>) o; //調用外部類的getEntry方法 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(); } } /** * Save the state of the <tt>HashMap</tt> instance to a stream (i.e., * serialize it). * * @serialData The <i>capacity</i> of the HashMap (the length of the * bucket array) is emitted (int), followed by the * <i>size</i> (an int, the number of key-value * mappings), followed by the key (Object) and value (Object) * for each key-value mapping. The key-value mappings are * emitted in no particular order. */ private void writeObject(java.io.ObjectOutputStream s) throws IOException { Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null; //調用默認的序列化流(序列化threshold, loadfactor等私有變量) s.defaultWriteObject(); // 序列化數組長度 s.writeInt(table.length); // 序列化鍵值對數 s.writeInt(size); // 序列化鍵值對值(非引用) 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; /** * 反序列化 */ private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // 根據私有成員建立HashMap s.defaultReadObject(); //根據數組長度初始化數組 int numBuckets = s.readInt(); table = new Entry[numBuckets]; //鉤子方法(子類若是要在初始化以前處理某些業務,可覆寫該方法) init(); // Give subclass a chance to do its thing. //讀取要存儲鍵值對的數量 int size = s.readInt(); // 根據鍵值對數量從流中循環讀取並創建鍵值對 for (int i=0; i<size; i++) { K key = (K) s.readObject(); V value = (V) s.readObject(); putForCreate(key, value); } } // These methods are used when serializing HashSets int capacity() { return table.length; } float loadFactor() { return loadFactor; } }