LinkedHashMap
如何保障有序的遍歷前一篇《JDK容器學習之LinkedHashMap (一):底層存儲結構分析》 中介紹了LinkedHashMap繼承自
HashMap
,且內部維護一個雙向鏈表,那麼其遍歷方式是否就是對這個雙向鏈表的遍歷呢?java
Map.Entry
進行遍歷public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es; return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es; } final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> { public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } public final Iterator<Map.Entry<K,V>> iterator() { return new LinkedEntryIterator(); } public final boolean contains(Object o) { // ... } public final boolean remove(Object o) { // ... } public final Spliterator<Map.Entry<K,V>> spliterator() { // ... } public final void forEach(Consumer<? super Map.Entry<K,V>> action) { // ... } } final class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map.Entry<K,V>> { public final Map.Entry<K,V> next() { return nextNode(); } }
上面給出關鍵的鏈路,entrySet
方法調用,首次會建立一個LinkedEntrySet
, 內部實現迭代器 LinkedEntryIterator
數據結構
因此迭代的主要邏輯就是LinkedEntryIterator
的實現方式了學習
abstract class LinkedHashIterator { LinkedHashMap.Entry<K,V> next; LinkedHashMap.Entry<K,V> current; int expectedModCount; LinkedHashIterator() { // 保證從鏈表的頭開始掃描 next = head; expectedModCount = modCount; current = null; } public final boolean hasNext() { return next != null; } 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; } 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; } }
迭代器的實現也比較清楚,首先是在構造器中,將next
指向雙向鏈表的頭head
this
nextNode
方法中,返回next
節點,並將next指向鏈表的下一個節點.net
public Set<K> keySet() { Set<K> ks; return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks; } final class LinkedKeySet extends AbstractSet<K> { public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } public final Iterator<K> iterator() { return new LinkedKeyIterator(); } public final boolean contains(Object o) { return containsKey(o); } public final boolean remove(Object key) { return removeNode(hash(key), key, null, false, true) != null; } public final Spliterator<K> spliterator() { // xxx } public final void forEach(Consumer<? super K> action) { // xxx } } final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> { public final K next() { return nextNode().getKey(); } }
從上面的調用鏈來看,迭代邏輯和上面同樣,惟一的區別是根據key進行迭代時,迭代器的next()
方法直接返回Node節點的key,而以前是返回整個Node節點code
基本邏輯同上,省略blog
從遍歷的邏輯來看,LinkedHashMap
的遍歷實際上就是遍歷內部維護的雙向鏈表繼承
掃一掃二維碼,關注小灰灰blog
rem