LinkedHashMap源碼學習

描述

  • 能夠按照添加元素的順序對元素進行迭代的HashMap的子類.
  • 注意,上面說的是加元素的順序.也就是說,更新元素時,是不會影響遍歷結構的的.除非設置參數accessOrdertrue,將更新元素放置到隊末.
  • 這個類沒有對其父類HashMap進行過多重寫.主要經過實現afterNode*相關方法,在數據結構變動後,進行後置的鏈表結構更新進行維護.

經常使用與關鍵方法

linkNodeLast方法

描述:

  • 負責初始化成員變量headtail.
  • headtail初始化完成後,負責將目標元素p鏈接到tail並更新原有tail到目標元素p

代碼:

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    // 緩存尾部
    LinkedHashMap.Entry<K,V> last = tail;
    // 更新尾部到新元素
    tail = p;
    // 判斷老尾部是否已經初始化
    if (last == null)
        // 老尾部爲初始化,表明頭部也沒初始化.進行初始化操做
        head = p;
    else {
        // 初始化以完成,將p連接到老尾部以後
        p.before = last;
        last.after = p;
    }
}

transferLinks方法

描述:

使用dst替換src在雙向鏈表中的位置java

代碼:

private void transferLinks(LinkedHashMap.Entry<K,V> src,
                           LinkedHashMap.Entry<K,V> dst) {
    // 同步before,同時保存到局部變量
    LinkedHashMap.Entry<K,V> b = dst.before = src.before;
    // 同步after,同時保存到局部變量
    LinkedHashMap.Entry<K,V> a = dst.after = src.after;
    // 檢查before
    if (b == null)
        // 沒有before.將dst設置爲head節點
        head = dst;
    else
        // 有before,將before與dst關聯
        b.after = dst;
    // 檢查after
    if (a == null)
        // 沒有after,將dst做爲tail節點
        tail = dst;
    else
        // 有after,將after與dst鏈接
        a.before = dst;
}

newNode方法

描述:

重寫了父類newNode方法.擴展雙向鏈表的鏈接操做.返回了HashMap.Node的子類節點LinkedHashMap.Entry.node

代碼:

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p =
        new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    // 建立的新節點.直接連接到末端節點上
    linkNodeLast(p);
    return p;
}

replacementNode方法

描述:

擴展雙向鏈表替換節點的操做.這個方法用於父類HashMapHashMap.TreeNode替換爲HashMap.Node時調用,這裏進行了重寫,使用帶有雙向鏈表的LinkedHashMap.Entry做爲返回值
注意: 這裏HashMap.TreeNode是實現了LinkedHashMap.Entry的.也就是參數p,他能夠直接強轉爲實現類LinkedHashMap.Entry算法

代碼:

Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
    LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
    LinkedHashMap.Entry<K,V> t =
        new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
    // 替換節點
    transferLinks(q, t);
    return t;
}

newTreeNode方法

描述:

重寫了父類方法newTreeNode.擴展雙向鏈表的鏈接操做.一樣,由於HashMap.TreeNode實現LinkedHashMap.Entry.能夠直接經過linkNodeLast方法進行鏈接操做緩存

代碼:

TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
    TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
    linkNodeLast(p);
    return p;
}

replacementTreeNode方法

描述:

replacementNode.擴展雙向鏈表替換節點的操做.只是節點類型變成了TreeNode.又由於他是LinkedHashMap.Entry的子類,能夠直接交給transferLinks使用.進行雙向鏈表替換操做數據結構

代碼:

TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
    LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
    TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
    transferLinks(q, t);
    return t;
}

afterNodeRemoval方法

描述:

刪除節點後調用.進行雙向鏈表同步code

代碼:

void afterNodeRemoval(Node<K,V> e) { // unlink
    // b - before節點
    // p - 被刪除節點
    // a - after節點
    LinkedHashMap.Entry<K,V> p =
        (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    // 清除p的雙端引用
    p.before = p.after = null;
    
    // 判斷before是否存在
    if (b == null)
        // 沒有before
        // 設置a爲head
        head = a;
    else
        // 存在before
        // 鏈接b->a.注意,這是單向鏈接,如今還沒法確認a是否存在.若是a爲空,b就是鏈表中的惟一節點.after屬性爲null
        b.after = a;
    // 判斷a是否爲空
    if (a == null)
        // a爲空
        // tail設置爲b
        tail = b;
    else
        // a存在
        // 鏈接 a->b.注意,這裏也是單向鏈接.若是b是空的話,a如今就是head且before屬性是null
        a.before = b;
}

afterNodeAccess方法

描述:

更新節點後調用.進行雙向鏈表同步對象

代碼:

void afterNodeAccess(Node<K,V> e) { // move node to last
    // oldTail.老尾部緩存
    LinkedHashMap.Entry<K,V> last;
    // 判斷accessOrder.即按照訪問(更新)順序排列
    // 獲取老尾部
    // 判斷當前元素是否是尾部元素
    if (accessOrder && (last = tail) != e) {
        // accessOrder==true且e不要尾部元素
        
        // b - fefore
        // p - 當前元素
        // a - after
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        
        // 由於p將變爲尾部元素,因此直接設置p.after爲null.
        p.after = null;
        
        // 判斷b
        if (b == null)
            // b爲null,p節點就是head節點
            // a做爲頭部節點
            head = a;
        else
            // b不爲空
            // 鏈接b->a. 注意,這裏是單向鏈接.a可能爲null,a.before的鏈接交給後續判斷
            b.after = a;
        
        // 判斷a
        if (a != null)
            // a不爲空
            // a->b.注意,這裏是單向連接.b多是null.b.after的鏈接交給後續判斷
            a.before = b;
        else
            // a爲空.p節點就是tail節點
            // 這裏有兩個分支,須要判斷b是否爲空.此處a已經爲空,若是b也爲空,說明p是列表中的惟一節點.這個判斷委託到後續判斷中處理
            // 此時,last變量已經失去意義,它與p爲同一對象.
            // 這裏說一下賦值last = b;的做用.注意,這是本人猜想!
            // 是爲了統一算法的外在樣式.由於變量last在在本方法中是不會爲空的,且在全部的情形中,都會調用p.before = last;last.after = p;進行鏈接(除了p是惟一元素的狀況).
            // 那麼在b存在的時候,再次與p進行鏈接,在鏈表結構上也是沒有問題的,統一被視做被操做元素的前一個元素
            last = b;
        if (last == null)
            // p是惟一元素
            head = p;
        else {
            // 鏈接到尾部節點
            p.before = last;
            last.after = p;
        }
        // 更新尾部節點到p
        tail = p;
        // 修改計數++
        ++modCount;
    }
}

內部類

LinkedHashIterator

描述:

封裝了針對鏈表結構的迭代器.並向子類提供了共有的擴展方法.繼承

代碼:

abstract class LinkedHashIterator {
    LinkedHashMap.Entry<K,V> next;
    LinkedHashMap.Entry<K,V> current;
    int expectedModCount;

    LinkedHashIterator() {
        // 初始化next節點爲當前head
        next = head;
        expectedModCount = modCount;
        current = null;
    }

    public final boolean hasNext() {
        return next != null;
    }

    final LinkedHashMap.Entry<K,V> nextNode() {
        // 緩存next
        LinkedHashMap.Entry<K,V> e = next;
        // fast-fail
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        // next爲空
        if (e == null)
            throw new NoSuchElementException();
        // 設置當前
        current = e;
        // 更新next到下一個
        next = e.after;
        return e;
    }

    public final void remove() {
        // 獲取當前
        Node<K,V> p = current;
        // null判斷
        if (p == null)
            throw new IllegalStateException();
        // fast-fail
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        // 迭代器置空
        current = null;
        // 獲取key
        K key = p.key;
        // 調用父類的removeNode方法進行節點刪除
        removeNode(hash(key), key, null, false, false);
        // 同步更新計數
        expectedModCount = modCount;
    }
}

內部類

LinkedHashIterator實現

描述:

分別繼承了LinkedHashIterator並使用前者的nextNode方法返回不一樣數據rem

代碼:

final class LinkedKeyIterator extends LinkedHashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().getKey(); }
}

final class LinkedValueIterator extends LinkedHashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}

final class LinkedEntryIterator extends LinkedHashIterator
    implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}
相關文章
相關標籤/搜索