【集合框架】JDK1.8原始碼分析之HashMap & LinkedHashMap迭代器(三)

leesf發表於2016-03-07

一、前言

  在遍歷HashMap與LinkedHashMap時,我們通常都會使用到迭代器,而HashMap的迭代器與LinkedHashMap迭代器是如何工作的呢?下面我們來一起分析分析。

二、迭代器繼承圖

  

  

三、HashMap迭代器

  3.1 HashIterator

  HashIterator是一個抽象類,封裝了迭代器內部工作的一些操作。

  HashIterator類屬性

abstract class HashIterator {
    // 下一個結點
    Node<K,V> next;        // next entry to return
    // 當前結點
    Node<K,V> current;     // current entry
    // 期望的修改次數
    int expectedModCount;  // for fast-fail
    // 當前桶索引
    int index;             // current slot
}
View Code

  說明:其中expectedModCount屬性主要用於在遍歷HashMap同時,程式對其結構是否進行了修改。若遍歷同時修改了,則會丟擲異常。

  HashIterator建構函式 

HashIterator() {
        // 成員變數賦值
        expectedModCount = modCount;
        Node<K,V>[] t = table;
        current = next = null;
        index = 0;
        // table不為空並且大小大於0
        if (t != null && size > 0) { // advance to first entry
            // 找到table陣列中第一個存在的結點,即找到第一個具有元素的桶
            do {} while (index < t.length && (next = t[index++]) == null);
        }
    }
View Code

  說明:next將表示第一個非空桶中的第一個結點,index將表示下一個桶。

  HashIterator核心函式分析

  1. hasNext函式

// 是否存在下一個結點
public final boolean hasNext() {
    return next != null; 
}
View Code

  2. nextNode函式 

final Node<K,V> nextNode() {
    // 記錄next結點
    Node<K,V> e = next;
    // 若在遍歷時對HashMap進行結構性的修改則會丟擲異常
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 下一個結點為空,丟擲異常
    if (e == null)
        throw new NoSuchElementException();
    // 如果下一個結點為空,並且table表不為空;表示桶中所有結點已經遍歷完,需尋找下一個不為空的桶
    if ((next = (current = e).next) == null && (t = table) != null) {
        // 找到下一個不為空的桶
        do {} while (index < t.length && (next = t[index++]) == null);
    }
    return e;
}
View Code

  說明:nextNode函式遮蔽掉了桶的不同所帶來的差異,就好像所有元素在同一個桶中,依次進行遍歷。

  3. remove函式

public final void remove() {
    Node<K,V> p = current;
    // 當前結點為空,丟擲異常
    if (p == null)
        throw new IllegalStateException();
    // 若在遍歷時對HashMap進行結構性的修改則會丟擲異常
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 當前結點為空
    current = null;
    K key = p.key;
    // 移除結點
    removeNode(hash(key), key, null, false, false);
    // 賦最新值
    expectedModCount = modCount;
}
View Code

  3.2 KeyIterator

  KeyIterator類是鍵迭代器,繼承自HashIterator,實現了Iterator介面,可以對HashMap中的鍵進行遍歷。

  類定義 

final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
}
View Code

  3.3 ValueIterator

  ValueIterator類是值迭代器,繼承自HashIterator,實現了Iterator介面,與KeyIterator類似,對值進行遍歷。  

final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}
View Code

  3.4 EntryIterator

  EntryIterator類是結點迭代器,繼承自HashIterator,實現了Iterator介面,與KeyIterator、ValueIterator類似,對結點進行遍歷。 

final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}
View Code

四、LinkedHashMap迭代器

  4.1 LinkedHashIterator

  LinkedHashIterator是LinkedHashMap的迭代器,為抽象類,用於對LinkedHashMap進行迭代。 

  LinkedHashIterator類屬性

abstract class LinkedHashIterator {
    // 下一個結點
    LinkedHashMap.Entry<K,V> next;
    // 當前結點
    LinkedHashMap.Entry<K,V> current;
    // 期望的修改次數
    int expectedModCount;
}
View Code

  LinkedHashIterator建構函式  

LinkedHashIterator() {
    // next賦值為頭結點
    next = head;
    // 賦值修改次數
    expectedModCount = modCount;
    // 當前結點賦值為空
    current = null;
}
View Code

  LinkedHashIterator核心函式

  hasNext函式

// 是否存在下一個結點
public final boolean hasNext() {
    return next != null;
}
View Code

  nextNode函式 

final LinkedHashMap.Entry<K,V> nextNode() {
    LinkedHashMap.Entry<K,V> e = next;
    // 檢查是否存在結構性修改
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 當前結點是否為空
    if (e == null)
        throw new NoSuchElementException();
    // 賦值當前節點
    current = e;
    // 賦值下一個結點
    next = e.after;
    return e;
}
View Code

  說明:由於所有的結點構成雙連結串列結構,所以nextNode函式也很好理解,直接取得下一個結點即可。

public final void remove() {
    // 儲存當前結點
    Node<K,V> p = current;
    if (p == null)
        throw new IllegalStateException();
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    current = null;
    K key = p.key;
    // 移除結點
    removeNode(hash(key), key, null, false, false);
    // 更新最新修改數
    expectedModCount = modCount;
}
View Code

  4.2 LinkedKeyIterator

  LinkedHashMap的鍵迭代器,繼承自LinkedHashIterator,實現了Iterator介面,對LinkedHashMap中的鍵進行迭代。 

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

  4.3 LinkedValueIterator

  LinkedHashMap的值迭代器,繼承自LinkedHashIterator,實現了Iterator介面,對LinkedHashMap中的值進行迭代。

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

  4.4 LinkedEntryIterator

  LinkedHashMap的結點迭代器,繼承自LinkedHashIterator,實現了Iterator介面,對LinkedHashMap中的結點進行迭代。 

final class LinkedEntryIterator extends LinkedHashIterator
    implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}
View Code

五、總結

  HashMap迭代器與LinkedHashMap迭代器有很多相似的地方,對比進行學習效果更佳。迭代器要遮蔽掉底層的細節,提供統一的介面供使用者訪問。HashMap與LinkedHashMap的迭代器原始碼分析就到此為止,還是很簡單的,謝謝各位園友觀看~

 

相關文章