LinkedHashMap 原始碼分析 (jdk1.8)
阿新 • • 發佈:2018-12-16
類繼承關係:
什麼是LinkedHashMap
雜湊表和Map介面的連結串列實現,與HashMap的不同之處 在於它維護著一個雙向連結串列,這個連結串列定義了迭代排序,通常是插入順序。 * 如果將鍵重新插入中,則插入順序不受影響。
LinkedHashMap資料結構
LinkedHashMap是基於HashMap實現的,只是在HashMap的基礎上增加了雙向連結串列而已。 (這裡直接把上一篇的HashMap裡的資料結構圖簡單改了下)
原始碼分析:
1.類繼承實現
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{ //方法.... }
LinkedHashMap繼承HashMap所具有的特性基本一致,這裡不重複了。(點選跳轉Java集合原始碼實現三:HashMap(jdk1.8))。
2.成員變數
/**
* 首節點
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 尾節點
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* 排序規則方式
* true 按訪問順序排序
* false 預設按插入順序排序
*/
final boolean accessOrder;
在hashMap的基礎上又擴充套件了3個屬性,用於雙向連結串列。
3.LinkedHashMap中的連結串列節點
/**
* 繼承HashMap.Node
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
//before當前元素的上一個節點
//after當前元素的下一個節點
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
4.主要方法
構造方法
1.
/**
* 呼叫HashMap的構造方法
*/
public LinkedHashMap() {
super();
//預設按插入順序排序
accessOrder = false;
}
2.
/**
* 呼叫HashMap的構造方法
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
//預設按插入順序排序
accessOrder = false;
}
3.
/**
* 呼叫HashMap的構造方法
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
//預設按插入順序排序
accessOrder = false;
}
4.
/**
* 呼叫HashMap的構造方法
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
//預設按插入順序排序
accessOrder = false;
putMapEntries(m, false);
}
5.
/**
* 呼叫HashMap的指定引數的構造方法
* 並且指定排序方式
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
新增,刪除方法
LinkedHashMap中並沒有重寫父類HashMap的put,remove等方法。均是呼叫其父類的方法實現。
afterNodeAccess方法(移動節點到最後的方法)
LinkedHashMap通過重寫afterNodeAccess方法,使put()方法將節點插入到尾部。這也就是HashMap中afterNodeAccess()為空方法的原因,它是為LinkedHashMap服務的。
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
//當accessOrder為true 並且e不是最後一個節點的時
if (accessOrder && (last = tail) != e) {
//a為p的下一個節點
//b為p的上一個節點
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//p的下一個節點置null
p.after = null;
//b==null,即當前節點為首節點,更新首節點為a
if (b == null)
head = a;
else//當前節點不是首節點,修改b的下一個節點為a
b.after = a;
if (a != null) //a!=null,即當前結點不是尾節點
a.before = b;//更新a的上一個節點為b
else
last = b;//最後一個節點更新為b
if (last == null)//如果最後一個節點為null
head = p;//首節點更新為p
else {
p.before = last;//p的上一個節點更新為最後一個節點
last.after = p;//最後一個節點的下一個節點更新為p
}
//尾節點修改為p
tail = p;
//操作次數增加
++modCount;
}
}
afterNodeRemoval方法
void afterNodeRemoval(Node<K,V> e) { // unlink
//a為p的下一個節點
//b為p的上一個節點
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null) //b為null,即當前節點為首節點
head = a;//更新首節點為a
else//即當前節點不是首節點
b.after = a;//更新b的下一個節點為a
if (a == null)//a為null,當前節點為尾節點
tail = b;//更新尾節點為b
else//即當前節點不是尾節點
a.before = b;//更新a的上一個節點為b
}
在移除節點時通過呼叫afterNodeRemoval()來更新首尾節點,與afterNodeAccess()同理。
獲取元素
/**
* 獲取元素
*/
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
LinkedHashMap獲取元素與HashMap基本相同,getNode()與hash()方法都是呼叫HashMap的方法,唯一區別是具有排序方式,如果accessOrder為false,則不需要修改獲取的元素的順序,按預設的插入順序排序,如果為true,需要呼叫afterNodeAccess()把獲取的節點移動到最後。 --------------------- 原文:https://blog.csdn.net/qq_23830637/article/details/79020118