LinkedHashMap 是对 HashMap 的封装和拓展,在保留了 HashMap 原有功能的基础上,加了一些链表相关的属性,用来记录 HashMap 元素的先后顺序,这样如果要根据(节点插入或访问)顺序访问节点时,只要去遍历链表即可。
默认元素插入顺序排序:
@Test public void test1() { LinkedHashMap map = new LinkedHashMap(); map.put("222", 222); map.put("111", 111); map.put("333", 333); System.out.println("遍历迭代器:"); Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); System.out.println(entry.getKey() + ": " + entry.getValue()); } System.out.println("遍历map:"); map.forEach((k, v) -> { System.out.println(k + ": " + v); }); /** * 执行结果: * * 遍历迭代器: * 222: 222 * 111: 111 * 333: 333 * 遍历map: * 222: 222 * 111: 111 * 333: 333 */ }
按照元素访问顺序排序:
@Test public void test2() { LinkedHashMap map = new LinkedHashMap(4, 0.8f, true); map.put("222", 222); map.put("111", 111); map.put("333", 333); map.get("333"); map.get("111"); map.get("222"); System.out.println("遍历迭代器:"); Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); System.out.println(entry.getKey() + ": " + entry.getValue()); } System.out.println("遍历map:"); map.forEach((k, v) -> { System.out.println(k + ": " + v); }); /** * 执行结果: * * 遍历迭代器: * 333: 333 * 111: 111 * 222: 222 * 遍历map: * 333: 333 * 111: 111 * 222: 222 */ }
static class Entry<K,V> extends HashMap.Node<K,V> { // before 指向此节点的前一个节点 // after 指向此节点的后一个节点 Entry<K,V> before, after; // Entry 构造方法,内部是调用了父类 HashMap 的构造方法 Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }
// LinkedHashMap 中所有节点元素的 key 集合 final class LinkedKeySet extends AbstractSet<K> { public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } // 获取 key 迭代器 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() { return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT); } // 遍历所有 key public final void forEach(Consumer<? super K> action) { if (action == null) throw new NullPointerException(); int mc = modCount; for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) action.accept(e.key); // 遍历时不能修改该 LinkedHashMap 对象 if (modCount != mc) throw new ConcurrentModificationException(); } }
// LinkedHashMap 中所有节点元素的 value 集合 final class LinkedValues extends AbstractCollection<V> { public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } public final Iterator<V> iterator() { return new LinkedValueIterator(); } public final boolean contains(Object o) { return containsValue(o); } public final Spliterator<V> spliterator() { return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED); } // 遍历所有 value public final void forEach(Consumer<? super V> action) { if (action == null) throw new NullPointerException(); int mc = modCount; for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) action.accept(e.value); if (modCount != mc) throw new ConcurrentModificationException(); } }
// LinkedHashMap 中所有节点元素的 entry 对象集合 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) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>) o; Object key = e.getKey(); Node<K,V> candidate = getNode(hash(key), key); return candidate != null && candidate.equals(e); } public final boolean remove(Object o) { if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>) o; Object key = e.getKey(); Object value = e.getValue(); return removeNode(hash(key), key, value, true, true) != null; } return false; } public final Spliterator<Map.Entry<K,V>> spliterator() { return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT); } public final void forEach(Consumer<? super Map.Entry<K,V>> action) { if (action == null) throw new NullPointerException(); int mc = modCount; for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) action.accept(e); if (modCount != mc) throw new ConcurrentModificationException(); } }
// 迭代器 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 指向下一个要遍历的节点 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; } }
// key 迭代器 final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> { // 返回下一个节点的 key public final K next() { return nextNode().getKey(); } }
// value 迭代器 final class LinkedValueIterator extends LinkedHashIterator implements Iterator<V> { // 返回下一个节点的 value 值 public final V next() { return nextNode().value; } }
// entry 迭代器 final class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map.Entry<K,V>> { // 返回下一个节点的 entry 对象 public final Map.Entry<K,V> next() { return nextNode(); } }
// 双向链表的头结点 transient LinkedHashMap.Entry<K,V> head; // 双向链表的尾结点 transient LinkedHashMap.Entry<K,V> tail; // 链表节点的排序规则: // accessOrder 为 true,根据访问顺序排序 // accessOrder 为 false,根据插入顺序排序 final boolean accessOrder;
// 默认是插入排序 public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } // 默认是插入排序 public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } // 默认是插入排序 public LinkedHashMap() { super(); accessOrder = false; } // 默认是插入排序 public LinkedHashMap(Map<? extends K, ? extends V> m) { super(); accessOrder = false; putMapEntries(m, false); } // 可以指定元素排序方式 accessOrder /** * Constructs an empty <tt>LinkedHashMap</tt> instance with the * specified initial capacity, load factor and ordering mode. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @param accessOrder the ordering mode - <tt>true</tt> for * access-order, <tt>false</tt> for insertion-order * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
// 将节点 p 插入到链表的尾部 private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { // 记录旧的尾结点 LinkedHashMap.Entry<K,V> last = tail; // 更新 tail 指针,指向新插入的尾结点 p tail = p; // 如果插入前尾结点为 null,则表示链表当前无节点, // 则 head 结点也指向新插入的第一个节点 p if (last == null) head = p; else { // 链表不为空,直接将 p 插入到链表尾部 p.before = last; last.after = p; } }
// 用 dst 节点替换掉原来的 src 结点 private void transferLinks(LinkedHashMap.Entry<K,V> src, LinkedHashMap.Entry<K,V> dst) { // dst 的 before 指针指向 src 的 before 指针指向的节点 LinkedHashMap.Entry<K,V> b = dst.before = src.before; // dst 的 after 指针指向 src 的 after 指针指向的节点 LinkedHashMap.Entry<K,V> a = dst.after = src.after; // b 也指向 src.before // b 为 null,说明 src 是头结点,则现在 dst 也是头结点 if (b == null) head = dst; else // 如果 src 不是头结点,则因为 dst 已经指向了 src.before // 所以现在只要将 src.before 指向的前序节点的 after 指针指向 dst 即可完成 dst 节点插入操作 b.after = dst; // 同上 if (a == null) tail = dst; else a.before = dst; }
// 插入一个 HashMap 的节点到链表尾部,并返回插入后的 LinkedHashMap 节点 // LinkedHashMap 继承了 HashMap 类,在调用 put 方法时,会调用 newNode 方法 // linkNodeLast 方法是按照元素插入顺序进行排序(将元素插入到链表尾部) Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e); linkNodeLast(p); return p; }
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) { LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p; // 使用 HashMap 节点 next 构造一个 LinkedHashMap 节点 t LinkedHashMap.Entry<K,V> t = new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next); // 然后用新构造的节点 t 替换原来的节点 p transferLinks(q, t); // 返回新构造的节点 t return t; }
// 同 newNode 方法 TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) { TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next); linkNodeLast(p); return p; }
// 同 replacementNode 方法 TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) { LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p; TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next); transferLinks(q, t); return t; }
// 删除节点 e void afterNodeRemoval(Node<K,V> e) { // unlink // 将 e 转成 LinkedHashMap 节点 p // b 指向 p 的 before 节点 // a 指向 p 的 after 节点 LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; // 将 p.before 和 p.after 置空,即删除节点 p p.before = p.after = null; // 如果 b 为 null,表示 p 是链表第一个节点 if (b == null) // 则 head 指向 p 的下一个节点(p.after) head = a; else // 如果 b(p.before)不为空 // 则 p 的前序节点的(b) after 指针指向 p 的 after 节点(a) b.after = a; // 如果 a 为空,表示 p 是链表的最后一个节点 if (a == null) // 则 p.before 节点 b 现在是链表的最后一个节点,则更新 tail 节点 tail = b; else // 如果 a 不为空 // 则 p 的后继节点的(a) before 指针指向 p 的 before 节点(b) a.before = b; }
// 节点插入 HashMap 后的钩子方法 void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) { K key = first.key; removeNode(hash(key), key, null, false, true); } }
// 访问了 HashMap 节点后的钩子方法 void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; // 如果 accessOrder 为 true // 并且 e 不为链表的尾结点 // 则根据节点的访问顺序将节点排序,即将访问的节点 e 移动到链表的尾部 if (accessOrder && (last = tail) != e) { // 将节点 e 转成 LinkedHashMap 节点 p LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; // 要将节点 p 移动到链表的尾部 // 所以将 p.after 置空 p.after = null; // 如果 b 为 null,则 p 原先为头结点 if (b == null) // 现在要将 p 移动到链表尾部 // 则 p 的后继节点 a 现在为头结点 head = a; else // 如果 b 不为 null // 则将 p 的前序节点(b)的后继节点(b.after)指向 p 的后继节点(a) b.after = a; // 如果 a 不为空,则表示 p 不为尾结点 if (a != null) // 则将 p 的后继节点(a)的前序节点(a.before)指向 p 的前序节点(b) a.before = b; else // 否则 p 为链表的尾结点 // 使用 last 记录 p 的前序节点 b // (外层判断了 p 不能为尾节点) last = b; // 上面 last 记录了 p 的前序节点 b // 如果 b 为 null if (last == null) // 则链表中只有 p 这一个节点 head = p; else { // 将 p 移到链表尾部 p.before = last; last.after = p; } // 尾结点指向 p tail = p; ++modCount; } }
// 判断链表节点中是否有值为 value 的 public boolean containsValue(Object value) { // 从头结点开始遍历链表 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) { V v = e.value; // 如果链表节点元素值等于 value if (v == value || (value != null && value.equals(v))) // 则返回 true return true; } return false; }
// 根据 key 获取节点元素的值 public V get(Object key) { Node<K,V> e; // 根据 key 找不到元素,则直接返回 null if ((e = getNode(hash(key), key)) == null) return null; // 根据 key 找到了元素,则判断是否根据访问顺序排序 if (accessOrder) afterNodeAccess(e); return e.value; }
// 根据 key 获取节点元素的值,如果获取不到,则返回默认值 defaultValue public V getOrDefault(Object key, V defaultValue) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return defaultValue; if (accessOrder) afterNodeAccess(e); return e.value; }
transient Set<K> keySet; // 所有所有 key 的集合 public Set<K> keySet() { // 获取 keySet Set<K> ks = keySet; // 如果 keySet 为空 if (ks == null) { // 则构造一个 LinkedKeySet 对象 ks = new LinkedKeySet(); keySet = ks; } return ks; }
public Collection<V> values() { Collection<V> vs = values; if (vs == null) { vs = new LinkedValues(); values = vs; } return vs; }
public Set<Map.Entry<K,V>> entrySet() { Set<Map.Entry<K,V>> es; return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es; }
// 遍历 public void forEach(BiConsumer<? super K, ? super V> action) { if (action == null) throw new NullPointerException(); int mc = modCount; // 从 head 结点开始遍历节点 for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) action.accept(e.key, e.value); if (modCount != mc) throw new ConcurrentModificationException(); }
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { if (function == null) throw new NullPointerException(); int mc = modCount; for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) e.value = function.apply(e.key, e.value); if (modCount != mc) throw new ConcurrentModificationException(); }