HashMap是基於哈希表的Map接口的實現,提供全部的映射的操做,容許null值和null鍵,存儲的是一個鍵值對對象Entry<K,V>。java
是基於數組+鏈表的結構實現的,在內部維護一個table數組,數組的每一個位置存放一個鏈表的表頭節點,查找元素時,先經過hash算法獲得key的hash值,再經過hash值計算在數組中的索引位置,獲得鏈表的表頭節點,遍歷鏈表獲得value值。算法
/** * 默認的初始化容量,容量必須是2的冪 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 /** * 最大容量 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 默認的負載因子 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 空表實例 */ static final Entry<?,?>[] EMPTY_TABLE = {}; /** * 數組表,長度必須是2的冪 */ transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; /** * map中key-value鍵值對的個數 */ transient int size; /** * 下次擴容的閾值 */ int threshold; /** * 負載因子的值 */ final float loadFactor; /** * Hash表結構性修改次數,用於實現迭代器快速失敗行爲 */ transient int modCount;
/** * 主要初始化方法,自定義容量大小、自定義負載因子 */ 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); //取初始化大小的最小2的冪 } /** * 自定義容量大小、默認負載因子 */ public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * 默認容量大小、默認負載因子 */ public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } /** * Constructs a new <tt>HashMap</tt> with the same mappings as the * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with * default load factor (0.75) and an initial capacity sufficient to * hold the mappings in the specified <tt>Map</tt>. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */ public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); } /** * 計算cap的最小2的冪 * 例如 cap=0001 0101 0111 1111 * 最小2的冪=0010 0000 0000 0000 即最高位的前一位爲1,低位全是0 */ static final int tableSizeFor(int cap) { //例如 cap=0001 0101 0111 1111 int n = cap - 1; //處理cap=0001 0000 0000 0000的狀況 n |= n >>> 1; //n>>>1=0000 1010 1011 1111, n |= n >>> 1結果=0001 1... 即:最高2位爲1 n |= n >>> 2; //最高4位爲1 n |= n >>> 4; //最高8位爲1 n |= n >>> 8; //最高16位爲1 n |= n >>> 16; //最高32位爲1 即:0001 1111 1111 1111 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; //+1後爲0010 0000 0000 0000 }
/** * 用另外一個Map初始化HashMap */ public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; //設置默認的負載因子 putMapEntries(m, false); } /** * Implements Map.putAll and Map constructor * * @param m the map * @param evict false when initially constructing this map, else * true (relayed to method afterNodeInsertion). */ final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // table沒有初始化,則進行初始化 float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); }else if (s > threshold) resize(); //s大於HashMap的下次擴容閾值,則進行擴容 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { //遍歷入參的Map將節點加入HashMap K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } }
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); //初始化table } if (key == null) return putForNullKey(value); //添加key爲空的Entry int hash = hash(key); //計算key的hash值 int i = indexFor(hash, table.length); //根據hash值和數組的長度計算在數組中的位置 for (Entry<K,V> e = table[i]; e != null; e = e.next) { //遍歷鏈表,查詢是否有該key Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //有,則將value替換爲新值 V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; 修改次數加一 addEntry(hash, key, value, i); 添加entry return null; }
public V get(Object key) { if (key == null) return getForNullKey(); //key爲null時的處理方法 Entry<K,V> entry = getEntry(key); //普通查詢entry的方法 return null == entry ? null : entry.getValue(); } private V getForNullKey() { if (size == 0) { return null; } for (Entry<K,V> e = table[0]; e != null; e = e.next) { //遍歷table[0]的鏈表,查詢對應entry if (e.key == null) return e.value; } return null; } /** * Returns the entry associated with the specified key in the * HashMap. Returns null if the HashMap contains no mapping * for the key. */ final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); //計算key的hash值 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)))) //判斷key是否相等 return e; } return null; }