1. 程式人生 > >LinkedHashMap 原始碼分析 (jdk1.8)

LinkedHashMap 原始碼分析 (jdk1.8)

類繼承關係:

什麼是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