ArrayList源碼分析--jdk1.8
LinkedList源碼分析--jdk1.8
HashMap源碼分析--jdk1.8
AQS源碼分析--jdk1.8
ReentrantLock源碼分析--jdk1.8java
1. HashMap是能夠動態擴容的數組,基於數組、鏈表、紅黑樹實現的集合。
2. HashMap支持鍵值對取值、克隆、序列化,元素無序,key不可重複value可重複,均可爲null。
3. HashMap初始默認長度16,超出擴容2倍,填充因子0.75f。
4.HashMap當鏈表的長度大於8的且數組大小大於64時,鏈表結構轉變爲紅黑樹結構。node
數據結構是集合的精華所在,數據結構每每也限制了集合的做用和側重點,瞭解各類數據結構是咱們分析源碼的必經之路。
HashMap的數據結構以下:數組+鏈表+紅黑樹數組
/* * 用數組+鏈表+紅黑樹實現的集合,支持鍵值對查找 */ public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { private static final long serialVersionUID = 362498820763181265L; /** * 默認初始容量-必須是2的冪 * 1*2的4次方 默認長度16 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; /** * 最大容量 * 1*2的30次方 最大容量1073741824 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 默認的填充因子 0.75 * 負載因子0.75是對空間和時間效率的一個平衡選擇,建議你們不要修改,除非在時間和空間比較特殊的狀況下, * 若是內存空間不少而又對時間效率要求很高,能夠下降負載因子Load factor的值; * 相反,若是內存空間緊張而對時間效率要求不高,能夠增長負載因子loadFactor的值,這個值能夠大於1 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 當桶(bucket)上的節點數大於這個值時會轉成紅黑樹 */ static final int TREEIFY_THRESHOLD = 8; /** * 當桶(bucket)上的節點數小於這個值時樹轉鏈表 */ static final int UNTREEIFY_THRESHOLD = 6; /** * 桶中結構轉化爲紅黑樹對應的table的最小大小 */ static final int MIN_TREEIFY_CAPACITY = 64; /** * Node是單向鏈表,它實現了Map.Entry接口 */ static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; //構造函數Hash值 鍵 值 下一個節點 Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } // 實現接口定義的方法,且該方法不可被重寫 // 設值,返回舊值 public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } //構造函數Hash值 鍵 值 下一個節點 /* * 重寫父類Object的equals方法,且該方法不可被本身的子類再重寫 * 判斷相等的依據是,只要是Map.Entry的一個實例,而且鍵鍵、值值都相等就返回True */ public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } } /** *使用默認初始容量(16)和默認加載因子(0.75)構造一個空的 HashMap * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public HashMap() { // 初始化填充因子 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } /** * 使用默認加載因子0.75f,容量使用參數initialCapacity */ public HashMap(int initialCapacity) { // 調用HashMap(int, float)型構造函數 this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * @param initialCapacity the initial capacity 初始容量 * @param loadFactor the load factor 加載因子 * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ 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); // 初始化填充因子 this.loadFactor = loadFactor; // 初始化threshold大小 this.threshold = tableSizeFor(initialCapacity); } /** * @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; // 將m中的全部元素添加至HashMap中 putMapEntries(m, false); } /** * Returns a power of two size for the given target capacity. * 返回大於initialCapacity的最小的二次冪數值 * 16 32 64 128 */ 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; }
HashMap extends AbstractMap
AbstractMap extends Object
java中全部類都繼承Object,因此HashMap的繼承結構如上圖。
1. AbstractMap是一個抽象類,實現了Map<K,V>接口,Map<K,V>定義了一些Map(K,V)鍵值對通用方法,而AbstractMap抽象類中能夠有抽象方法,還能夠有具體的實現方法,AbstractMap實現接口中一些通用的方法,實現了基礎的/get/remove/containsKey/containsValue/keySet方法,HashMap再繼承AbstractMap,拿到通用基礎的方法,而後本身在實現一些本身特有的方法,這樣的好處是:讓代碼更簡潔,繼承結構最底層的類中通用的方法,減小重複代碼,從上往下,從抽象到具體,愈來愈豐富,可複用。
2.HashMap實現了Map<K,V>、Cloneable、Serializable接口
1)Map<K,V>接口,定義了Map鍵值對通用的方法,1.8中爲了增強接口的能力,使得接口能夠存在具體的方法,前提是方法須要被default或static關鍵字所修飾,Map中實現了一些通用方法實現,使接口更加抽象。
2)Cloneable接口,可使用Object.Clone()方法。
3)Serializable接口,序列化接口,代表該類能夠被序列化,什麼是序列化?簡單的說,就是可以從類變成字節流傳輸,反序列化,就是從字節流變成原來的類安全
1)V put(K key, V value);//map添加元素數據結構
/** * 新增元素 */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * Implements Map.put and related methods * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * onlyIfAbsent默認傳false,覆蓋更改現有值 * onlyIfAbsent傳true,不覆蓋更改現有值 * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //若是table爲空 或者 長度爲0 if ((tab = table) == null || (n = tab.length) == 0) //擴容 n = (tab = resize()).length; //計算index,並對null作處理 // (n - 1) & hash 肯定元素存放在哪一個桶中,桶爲空,新生成結點放入桶中(此時,這個結點是放在數組中) if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); // 桶中已經存在元素 else { Node<K,V> e; K k; //若是key存在 直接覆蓋 value // 比較桶中第一個元素(數組中的結點)的hash值相等,key相等 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) // 將第一個元素賦值給e,用e來記錄 e = p; //若是table[i]是紅黑樹 直接在紅黑樹中插入 // hash值不相等,即key不相等;爲紅黑樹結點 else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //若是是鏈表 則遍歷鏈表 else { // 在鏈表最末插入結點 for (int binCount = 0; ; ++binCount) { // 到達鏈表的尾部 if ((e = p.next) == null) { // 在尾部插入新結點 p.next = newNode(hash, key, value, null); // 結點數量達到閾值,轉化爲紅黑樹 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); // 跳出循環 break; } // 判斷鏈表中結點的key值與插入的元素的key值是否相等 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) // 相等,跳出循環 break; // 用於遍歷桶中的鏈表,與前面的e = p.next組合,能夠遍歷鏈表 p = e; } } // 表示在桶中找到key值、hash值與插入元素相等的結點 if (e != null) { // existing mapping for key // 記錄e的value V oldValue = e.value; // onlyIfAbsent爲false或者舊值爲null if (!onlyIfAbsent || oldValue == null) //用新值替換舊值 e.value = value; // 訪問後回調 afterNodeAccess(e); // 返回舊值 return oldValue; } } // 結構性修改 ++modCount; // 實際大小大於閾值則擴容 if (++size > threshold) resize(); // 插入後回調,用來回調移除最先放入Map的對象(LinkedHashMap中實現了,HashMap中爲空實現) afterNodeInsertion(evict); return null; } static final int hash(Object key) { int h; // h = key.hashCode() 爲第一步 取hashCode值 // h ^ (h >>> 16) 爲第二步 高位參與運算 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
2)putAll(Map<? extends K, ? extends V> m);//添加Map所有元素app
/** * 添加Map所有元素 */ public void putAll(Map<? extends K, ? extends V> m) { putMapEntries(m, true); } /** * 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) { // 判斷table是否已經初始化 if (table == null) { // pre-size // 未初始化,s爲m的實際元素個數 float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); // 計算獲得的t大於閾值,則初始化閾值 if (t > threshold) threshold = tableSizeFor(t); } // 已初始化,而且m元素個數大於閾值,進行擴容處理 else if (s > threshold) resize(); // 將m中的全部元素添加至HashMap中 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } } /** * 擴容 * ①.在jdk1.8中,resize方法是在hashmap中的鍵值對大於閥值時或者初始化時,就調用resize方法進行擴容; * ②.每次擴展的時候,都是擴展2倍:1六、3二、6四、128... * ③.擴展後Node對象的位置要麼在原位置,要麼移動到原偏移量兩倍(2次冪)的位置。 * @return the table */ final Node<K,V>[] resize() { Node<K,V>[] oldTab = table;//oldTab指向hash桶數組 int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) {//若是oldCap大於的話,就是hash桶數組不爲空 if (oldCap >= MAXIMUM_CAPACITY) {//若是大於最大容量了,就賦值爲整數最大的閥值 threshold = Integer.MAX_VALUE; return oldTab; } //若是當前hash桶數組的長度在擴容後仍然小於最大容量 而且oldCap大於默認值16,就擴充爲原來的2倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold 雙倍擴容閥值threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } //計算新的resize上限 if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];//新建hash桶數組 table = newTab;//將新數組的值複製給舊的hash桶數組 if (oldTab != null) {//進行擴容操做,複製Node對象值到新的hash桶數組 //把每一個bucket都移動到新的buckets中 for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) {//若是舊的hash桶數組在j結點處不爲空,複製給e oldTab[j] = null;//將舊的hash桶數組在j結點處設置爲空,方便gc if (e.next == null)//若是e後面沒有Node結點 newTab[e.hash & (newCap - 1)] = e;//直接對e的hash值對新的數組長度求模得到存儲位置 else if (e instanceof TreeNode)//若是e是紅黑樹的類型,那麼添加到紅黑樹中 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order 鏈表優化重hash的代碼塊 Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next;//將Node結點的next賦值給next if ((e.hash & oldCap) == 0) {//若是結點e的hash值與原hash桶數組的長度做與運算爲0 原索引 if (loTail == null)//若是loTail爲null loHead = e;//將e結點賦值給loHead else loTail.next = e;//不然將e賦值給loTail.next loTail = e;//而後將e複製給loTail } // 原索引+oldCap else {//若是結點e的hash值與原hash桶數組的長度做與運算不爲0 if (hiTail == null)//若是hiTail爲null hiHead = e;//將e賦值給hiHead else hiTail.next = e;//若是hiTail不爲空,將e複製給hiTail.next hiTail = e;//將e複製個hiTail } } while ((e = next) != null);//直到e爲空 //原索引放到bucket裏 if (loTail != null) {//若是loTail不爲空 loTail.next = null;//將loTail.next設置爲空 newTab[j] = loHead;//將loHead賦值給新的hash桶數組[j]處 } //原索引+oldCap放到bucket裏 if (hiTail != null) {//若是hiTail不爲空 hiTail.next = null;//將hiTail.next賦值爲空 newTab[j + oldCap] = hiHead;//將hiHead賦值給新的hash桶數組[j+舊hash桶數組長度] } } } } } return newTab; }
3)V putIfAbsent(K key, V value);//若是key存在,則跳過,不覆蓋value值,onlyIfAbsent傳true,不覆蓋更改現有值ide
/** * 若是key存在則跳過,不覆蓋value值,onlyIfAbsent傳true,不覆蓋更改現有值 * 若是key不存在則put * @param key * @param value * @return */ @Override public V putIfAbsent(K key, V value) { return putVal(hash(key), key, value, true, true); }
4)merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction);//用某種方法更新原來的value值函數
/** * 用某種方法更新原來的value值 * BiFunction支持函數式變成,lambda表達式,如:String::concat拼接 * @param key * @param value * @param remappingFunction * @return */ @Override public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { if (value == null) throw new NullPointerException(); if (remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0; TreeNode<K,V> t = null; Node<K,V> old = null;// 該key原來的節點對象 if (size > threshold || (tab = table) == null || (n = tab.length) == 0)//判斷是否須要擴容 n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode)// 取出old Node對象 old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else { Node<K,V> e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } } if (old != null) {//若是 old Node 存在 V v; if (old.value != null) // 若是old存在,執行lambda,算出新的val並寫入old Node後返回。 v = remappingFunction.apply(old.value, value); else v = value; if (v != null) { old.value = v; afterNodeAccess(old); } else removeNode(hash, key, null, false, true); return v; } if (value != null) { //若是old不存在且傳入的newVal不爲null,則put新的kv if (t != null) t.putTreeVal(this, tab, hash, key, value); else { tab[i] = newNode(hash, key, value, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); } return value; }
5)compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction);//根據已知的 k v 算出新的v並put源碼分析
/** * 根據已知的 k v 算出新的v並put。 * 若是根據key獲取的oldVal爲空則lambda中涉及到oldVal的計算會報空指針。 * 如:map.compute("a", (key, oldVal) -> oldVal + 1); 若是oldVal爲null,則空指針 * 源碼和merge相似 * BiFunction返回值做爲新的value,BiFunction有二個參數 * @param key * @param remappingFunction * @return */ @Override public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { if (remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0; TreeNode<K,V> t = null; Node<K,V> old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else { Node<K,V> e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } } V oldValue = (old == null) ? null : old.value; V v = remappingFunction.apply(key, oldValue); if (old != null) { if (v != null) { old.value = v; afterNodeAccess(old); } else removeNode(hash, key, null, false, true); } else if (v != null) { if (t != null) t.putTreeVal(this, tab, hash, key, v); else { tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); } return v; }
6)computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction);//當key不存在時才put,若是key存在則無效性能
/** * 當key不存在時才put,若是key存在則無效 * 如:computeIfAbsent(keyC, k -> genValue(k)); * Function返回值做爲新的value,Function只有一個參數 * @param key * @param mappingFunction * @return */ @Override public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { if (mappingFunction == null) throw new NullPointerException(); int hash = hash(key); Node<K,V>[] tab; Node<K,V> first; int n, i; int binCount = 0; TreeNode<K,V> t = null; Node<K,V> old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key); else { Node<K,V> e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } V oldValue; if (old != null && (oldValue = old.value) != null) { afterNodeAccess(old); return oldValue; } } V v = mappingFunction.apply(key); if (v == null) { return null; } else if (old != null) { old.value = v; afterNodeAccess(old); return v; } else if (t != null) t.putTreeVal(this, tab, hash, key, v); else { tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); return v; }
7)computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction);//compute方法的補充,若是key存在,則覆蓋新的BiFunction計算出的value值,若是不存在則跳過
/** * compute方法的補充,若是key存在,則覆蓋新的BiFunction計算出的value值,若是不存在則跳過 * @param key * @param remappingFunction * @return */ public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { if (remappingFunction == null) throw new NullPointerException(); Node<K,V> e; V oldValue; int hash = hash(key); if ((e = getNode(hash, key)) != null && (oldValue = e.value) != null) { V v = remappingFunction.apply(key, oldValue); if (v != null) { e.value = v; afterNodeAccess(e); return v; } else removeNode(hash, key, null, false, true); } return null; }
8)V replace(K key, V value);//替換新值
/** * 若是key存在不爲空,則替換新的value值 */ @Override public V replace(K key, V value) { Node<K,V> e; if ((e = getNode(hash(key), key)) != null) { V oldValue = e.value; e.value = value; afterNodeAccess(e); return oldValue; } return null; }
9)replace(K key, V oldValue, V newValue);//判斷oldValue是不是當前key的值,再替換新值
/** * 若是key存在不爲空而且oldValue等於當前key的值,則替換新的value值 */ @Override public boolean replace(K key, V oldValue, V newValue) { Node<K,V> e; V v; if ((e = getNode(hash(key), key)) != null && ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) { e.value = newValue; afterNodeAccess(e); return true; } return false; }
10)replaceAll(BiFunction<? super K, ? super V, ? extends V> function);//替換新值
/** * 根據lambda函數替換符合規則的值 */ @Override public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { Node<K,V>[] tab; if (function == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Node<K,V> e = tab[i]; e != null; e = e.next) { e.value = function.apply(e.key, e.value); } } if (modCount != mc) throw new ConcurrentModificationException(); } }
總結:
正常狀況下會擴容2倍,特殊狀況下(新擴展數組大小已經達到了最大值)則只取最大值1 << 30。
1)V remove(Object key); //根據key 刪除元素
/** * 根據key 刪除元素 */ public V remove(Object key) { Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; } /** * Implements Map.remove and related methods * * @param hash hash for key * @param key the key * @param value the value to match if matchValue, else ignored * @param matchValue if true only remove if value is equal * @param movable if false do not move other nodes while removing * @return the node, or null if none */ final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { Node<K,V>[] tab; Node<K,V> p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { Node<K,V> node = null, e; K k; V v; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; else if ((e = p.next) != null) { if (p instanceof TreeNode) node = ((TreeNode<K,V>)p).getTreeNode(hash, key); else { do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof TreeNode) ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; --size; afterNodeRemoval(node); return node; } } return null; }
2)remove(Object key, Object value); //根據key,value 刪除元素
/** * 根據key,value 刪除元素 */ @Override public boolean remove(Object key, Object value) { return removeNode(hash(key), key, value, true, true) != null; }
/** * 返回指定的值 */ public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } /** * @author jiaxiaoxian * @date 2019年2月12日 * 若是key不爲空則返回key的值,不然返回默認值 */ @Override public V getOrDefault(Object key, V defaultValue) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? defaultValue : e.value; }
/** * 返回全部key,以Set結構返回 */ public Set<K> keySet() { Set<K> ks; return (ks = keySet) == null ? (keySet = new KeySet()) : ks; }
/** * 複製,返回此HashMap 的淺拷貝 */ @SuppressWarnings("unchecked") @Override public Object clone() { HashMap<K,V> result; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } result.reinitialize(); result.putMapEntries(this, false); return result; }
/** * 清空HashMap */ public void clear() { Node<K,V>[] tab; modCount++; if ((tab = table) != null && size > 0) { size = 0; for (int i = 0; i < tab.length; ++i) tab[i] = null; } }
/** * 是否存在此key */ public boolean containsKey(Object key) { return getNode(hash(key), key) != null; }
/** * 是否存在此value */ public boolean containsValue(Object value) { Node<K,V>[] tab; V v; if ((tab = table) != null && size > 0) { for (int i = 0; i < tab.length; ++i) { for (Node<K,V> e = tab[i]; e != null; e = e.next) { if ((v = e.value) == value || (value != null && value.equals(v))) return true; } } } return false; }
/** * 返回key,value的Set結果 */ public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es; }
1)HashMap的key、value均可以存放null,key不可重複,value可重複,是數組鏈表紅黑樹的數據結構。 2)HashMap區別於數組的地方在於可以自動擴展大小,其中關鍵的方法就是resize()方法,擴容爲2倍。 3)HashMap因爲本質是數組,在不衝突的狀況下,查詢效率很高,hash衝突後會造成鏈表,查找時多一層 遍歷,當鏈表長度到8而且數組長度大於64,轉成紅黑樹存儲,提升查詢效率。 4)初始化數組時推薦給初始長度,反覆擴容會增長時耗,影響性能效率,HashMap須要注意負載因子0.75f, 初始16,當長度大於(16*0.75)12的時候會擴容爲32,因此初始長度設置須要卻別對待。 5)HashMap是一種散列表,採用(數組 + 鏈表 + 紅黑樹)的存儲結構。 6)當桶的數量大於64且單個桶中元素的數量大於8時,進行樹化。 7)當單個桶中元素數量小於6時,進行反樹化。 8)HashMap是非線程安全的容器。 9)HashMap查找添加元素的時間複雜度都爲O(1)。