本文版權歸 遠方的風lyh和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文鏈接,謝謝合作,如有錯誤之處忘不吝批評指正!
絮叨絮叨
首先呢,明白一點 LinkedHashMap是HashMap的子類,也就是說它就是一個HashMap(所以還是要對HashMap源碼有一定了解),至於它可以保證(有序)先后順序,只能說兒子比老子優秀!虎父無犬子,兒子在父親的基業上又有了獨到之處!原因呢?下面一起看看源碼((基於jdk1.8)就知曉了!(看源碼一定要有耐心,第一次看可能看不懂,后面再看可能還是看不懂,但是別放棄治療)。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { }
源碼分析
變量分析
LinkedHashMap在HashMap基礎上擴展的這兩個成員變量要特別注意,這兩個變量是保證有序的基礎
/** * The head (eldest) of the doubly linked list.
* 記錄第一個 key—value 對象關於LinkedHashMap.Entry<K,V>的結構接下來就會分析
*/
transient LinkedHashMap.Entry<K,V> head; /** * The tail (youngest) of the doubly linked list.
* 保存最后一個 key—value 對象 */ transient LinkedHashMap.Entry<K,V> tail;
LinkedHashMap.Entry<K,V>結構:
它繼承了HashMap.Node<K,V>, 添加了兩個LinkedHashMap.Entry<K,V> 用來記錄它的前一個 和后一個put進入來的key-value對象(LinkedHashMap.Entry<K,V>),在在結構設計上保證了LinkedHashMap有序的可實現
static class Entry<K,V> extends HashMap.Node<K,V> {
//它的前一個 和后一個put進入來的key-value對象 Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
附上HashMap.Node<K,V>
static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } //省略。。。。。。。 }
實現
了解完結構我們再來看看它在代碼中是如何實現的,LinkedHashMap是HashMap的子類 ,在放入key-value時,它復用了HashMap的put方法
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) //這里要格外注意 LinkedHashMap復寫了HashMap的 //newNode(hash, key, value, null) 方法 tab[i] = newNode(hash, key, value, null); //...... }
LinkedHashMap復寫了HashMap的newNode(hash, key, value, null) 方法,代碼如下:
1 Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { 2 LinkedHashMap.Entry<K,V> p = 3 new LinkedHashMap.Entry<K,V>(hash, key, value, e); 4 linkNodeLast(p); 5 return p; 6 } 7 /***有序的實現核心***/ 8 private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { 9 LinkedHashMap.Entry<K,V> last = tail; 10 tail = p; 11 if (last == null) 12 head = p; 13 else { 14 p.before = last; 15 last.after = p; 16 } 17 }
舉一個場景來說明上面的有序核心實現方法,比如說有這么一個場景: 一個班有 1號小明同學 2號張三 3號小紅 4號李四同學,老師要知道學生進入教師的先后順序。老師在黑板上寫了 兩個詞 head,tail兩個字段 規定:
1.第一個來的在 head來的在head、tail寫上自己的名字
2.第二個及后續到的, 看到黑板上的tail字段后,找到這個同學(這個同學記住我之后到的 after) 通知自己到了(並記住在我之前的是這個同學before) 並修改tail字段為自己的名字
例子:
1.小明同學 第一個到 ,在黑板上 head,tail 都寫下 小明
2.張三到了之后看到 tail是小明 記住 自己上一個(before)是小明 ,並修改tail為張三 ,通知小明,小明記下來自己的后面(afte)r是張三
3小紅到了看到tail是張三 記住自己上一個(before)是張三 並修改tail為小紅,通知張三,張三記下來自己的后面(after)是小紅
4李四到了。。。。。。。
老師來了上課 看到head上寫的是小明 並詢問 小明 你后面是誰 , 小明回:小紅 再詢問 小紅 ....知道 詢問到李四 結束
老師就知道了學生進入教室的順序 小明->張三->小紅->李四。