HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。
LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。通过维护一个双向链表实现。
需要在理解HashMap实现原理的基础上学习LinkedHashMap,
一、数据结构
实际上就是在HashMap的基础上加了LinkedList
(图片来自)
LinkedHashMap.Entry继承了HashMap.Node,并扩展了before ,after属性
static class Entryextends HashMap.Node { Entry before, after; Entry(int hash, K key, V value, Node next) { super(hash, key, value, next); } }
二、类
继承了HashMap
public class LinkedHashMapextends HashMap implements Map
三、属性
transient LinkedHashMap.Entryhead; transient LinkedHashMap.Entry tail; final boolean accessOrder;//true表示按照访问顺序迭代(最近访问在后),false时表示按照插入顺序(先插入在前,默认)
四、主要方法
put
/** * 直接使用HashMap的put方法 * 重写了newNode()方法:维护双向链表 * 重写了afterNodeAccess(e)方法:如果按访问顺序排序,把node移动到双链表的尾端 */ NodenewNode(int hash, K key, V value, Node e) { LinkedHashMap.Entry p = new LinkedHashMap.Entry (hash, key, value, e); linkNodeLast(p); return p; } private void linkNodeLast(LinkedHashMap.Entry p) { LinkedHashMap.Entry last = tail; tail = p; if (last == null) head = p; else { p.before = last; last.after = p; } } void afterNodeAccess(Node e) { // move node to last LinkedHashMap.Entry last; if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry p = (LinkedHashMap.Entry )e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; } }
get
/** * 重写了get方法 * 如果按访问顺序排序,把node移动到双链表的尾端 */ public V get(Object key) { Nodee; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder) afterNodeAccess(e);// 如果按访问顺序排序,把node移动到双链表的尾端 return e.value; }
remove
/** * 直接使用HashMap的remove方法 * 重写了afterNodeRemoval()方法:维护双端链表 */ void afterNodeRemoval(Nodee) { // unlink LinkedHashMap.Entry p = (LinkedHashMap.Entry )e, b = p.before, a = p.after; p.before = p.after = null; if (b == null) head = a; else b.after = a; if (a == null) tail = b; else a.before = b; }
遍历
/** * 主要看nextNode()方法 * 直接遍历的双向链表 */ final class LinkedKeyIterator extends LinkedHashIterator implements Iterator{ public final K next() { return nextNode().getKey(); } } final class LinkedValueIterator extends LinkedHashIterator implements Iterator { public final V next() { return nextNode().value; } } final class LinkedEntryIterator extends LinkedHashIterator implements Iterator > { public final Map.Entry next() { return nextNode(); } } abstract class LinkedHashIterator { LinkedHashMap.Entry next; LinkedHashMap.Entry current; int expectedModCount; LinkedHashIterator() { next = head; expectedModCount = modCount; current = null; } public final boolean hasNext() { return next != null; } final LinkedHashMap.Entry nextNode() { LinkedHashMap.Entry 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 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; } }