一、前言
在遍歷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 }
說明:其中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); } }
說明:next將表示第一個非空桶中的第一個結點,index將表示下一個桶。
HashIterator核心函式分析
1. hasNext函式
// 是否存在下一個結點 public final boolean hasNext() { return next != null; }
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; }
說明: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; }
3.2 KeyIterator
KeyIterator類是鍵迭代器,繼承自HashIterator,實現了Iterator介面,可以對HashMap中的鍵進行遍歷。
類定義
final class KeyIterator extends HashIterator implements Iterator<K> { public final K next() { return nextNode().key; } }
3.3 ValueIterator
ValueIterator類是值迭代器,繼承自HashIterator,實現了Iterator介面,與KeyIterator類似,對值進行遍歷。
final class ValueIterator extends HashIterator implements Iterator<V> { public final V next() { return nextNode().value; } }
3.4 EntryIterator
EntryIterator類是結點迭代器,繼承自HashIterator,實現了Iterator介面,與KeyIterator、ValueIterator類似,對結點進行遍歷。
final class ValueIterator extends HashIterator implements Iterator<V> { public final V next() { return nextNode().value; } }
四、LinkedHashMap迭代器
4.1 LinkedHashIterator
LinkedHashIterator是LinkedHashMap的迭代器,為抽象類,用於對LinkedHashMap進行迭代。
LinkedHashIterator類屬性
abstract class LinkedHashIterator { // 下一個結點 LinkedHashMap.Entry<K,V> next; // 當前結點 LinkedHashMap.Entry<K,V> current; // 期望的修改次數 int expectedModCount; }
LinkedHashIterator建構函式
LinkedHashIterator() { // next賦值為頭結點 next = head; // 賦值修改次數 expectedModCount = modCount; // 當前結點賦值為空 current = null; }
LinkedHashIterator核心函式
hasNext函式
// 是否存在下一個結點 public final boolean hasNext() { return next != null; }
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; }
說明:由於所有的結點構成雙連結串列結構,所以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; }
4.2 LinkedKeyIterator
LinkedHashMap的鍵迭代器,繼承自LinkedHashIterator,實現了Iterator介面,對LinkedHashMap中的鍵進行迭代。
final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> { public final K next() { return nextNode().getKey(); } }
4.3 LinkedValueIterator
LinkedHashMap的值迭代器,繼承自LinkedHashIterator,實現了Iterator介面,對LinkedHashMap中的值進行迭代。
final class LinkedValueIterator extends LinkedHashIterator implements Iterator<V> { public final V next() { return nextNode().value; } }
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(); } }
五、總結
HashMap迭代器與LinkedHashMap迭代器有很多相似的地方,對比進行學習效果更佳。迭代器要遮蔽掉底層的細節,提供統一的介面供使用者訪問。HashMap與LinkedHashMap的迭代器原始碼分析就到此為止,還是很簡單的,謝謝各位園友觀看~