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