diff --git a/docs/JDK/collection/LinkedHashMap.md b/docs/JDK/collection/LinkedHashMap.md index 7b24c88..8b56f76 100644 --- a/docs/JDK/collection/LinkedHashMap.md +++ b/docs/JDK/collection/LinkedHashMap.md @@ -1,13 +1,13 @@ -HashMap 大家都清楚,底层是 数组 + (红黑树 / 链表),**元素是无序的**,而 LinkedHashMap 则比 HashMap 多了这一个功能,并且,LinkedHashMap 的有序可以按两种顺序排列,一种是按照插入的顺序,一种是按照访问的顺序(初始化LinkedHashMap对象时设置accessOrder参数为true),而其内部是靠 建立一个双向链表 来维护这个顺序的,在每次插入、删除后,都会调用一个函数来进行 双向链表的维护,这也是实现 LRU Cache 功能的基础。 +HashMap 大家都清楚,底层是 数组 + (链表 / 红黑树),**元素是无序的**,而 LinkedHashMap 则比 HashMap 多了这一个功能,并且,LinkedHashMap 的有序可以按两种顺序排列,一种是按照插入的顺序,一种是按照访问的顺序(初始化LinkedHashMap对象时设置accessOrder参数为true),而其内部是靠 建立一个双向链表 来维护这个顺序的,在每次插入、删除后,都会调用一个函数来进行 双向链表的维护,这也是实现 LRU Cache 功能的基础。 先说几个比较重要的结论,大家可以根据这些结论从后面的源码解析中 得到证据。 1. LinkedHashMap 继承了 HashMap,所以和 HashMap 的底层数据结构是一样的,都是数组+链表+红黑树,扩容机制也一样; -2. LinkedHashMap 通过双向链表来维护数据的顺序; -3. LinkedHashMap 存储顺序与添加顺序默认是一样得,同时可以根据 accessOrder参数 来决定是否在访问时移动元素,以实现 LRU 功能。 +2. LinkedHashMap 是通过双向链表来维护数据的,与 HashMap 的拉链式存储不一样; +3. LinkedHashMap 存储顺序与添加顺序是一样得,同时可以根据 accessOrder参数 来决定是否在访问时移动元素,以实现 LRU 功能。 ```java public class LinkedHashMap extends HashMap implements Map { - + /** * 在 HashMap.Node节点 的基础上增加了 “前继节点” 和 “后继节点” 这种双向链表的功能特性 */ @@ -22,19 +22,19 @@ public class LinkedHashMap extends HashMap implements Map { * 记录这个 LinkedHashMap容器的 头节点 */ transient LinkedHashMap.Entry head; - + /** * 记录这个 LinkedHashMap容器的 尾节点 */ transient LinkedHashMap.Entry tail; - + /** * 是否根据访问 进行排序,true为是,可通过构造方法进行设置 */ final boolean accessOrder; - + // 下面是一些私有的内部公用方法 - + // 将元素连接到链表尾部 private void linkNodeLast(LinkedHashMap.Entry p) { LinkedHashMap.Entry last = tail; @@ -46,7 +46,7 @@ public class LinkedHashMap extends HashMap implements Map { last.after = p; } } - + // apply src's links to dst private void transferLinks(LinkedHashMap.Entry src, LinkedHashMap.Entry dst) { LinkedHashMap.Entry b = dst.before = src.before; @@ -60,22 +60,22 @@ public class LinkedHashMap extends HashMap implements Map { else a.before = dst; } - + // 下面是一些 重写的 HashMap 的 hook methods,其中 afterNodeInsertion、afterNodeRemoval // afterNodeAccess及方法,在每次插入、删除、访问后,都会回调 用来维护双向链表 - + void reinitialize() { super.reinitialize(); head = tail = null; } - + Node newNode(int hash, K key, V value, Node e) { LinkedHashMap.Entry p = new LinkedHashMap.Entry(hash, key, value, e); linkNodeLast(p); return p; } - + Node replacementNode(Node p, Node next) { LinkedHashMap.Entry q = (LinkedHashMap.Entry)p; LinkedHashMap.Entry t = @@ -83,21 +83,21 @@ public class LinkedHashMap extends HashMap implements Map { transferLinks(q, t); return t; } - + TreeNode newTreeNode(int hash, K key, V value, Node next) { TreeNode p = new TreeNode(hash, key, value, next); linkNodeLast(p); return p; } - + TreeNode replacementTreeNode(Node p, Node next) { LinkedHashMap.Entry q = (LinkedHashMap.Entry)p; TreeNode t = new TreeNode(q.hash, q.key, q.value, next); transferLinks(q, t); return t; } - - // 在删除元素之后,将元素从双向链表中删除 + + // 在删除元素之后,将元素从双向链表中删除 void afterNodeRemoval(Node e) { // unlink LinkedHashMap.Entry p = (LinkedHashMap.Entry)e, b = p.before, a = p.after; @@ -111,8 +111,8 @@ public class LinkedHashMap extends HashMap implements Map { else a.before = b; } - - // 可用于删除最老的元素 + + // 可用于删除最老的元素 void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry first; if (evict && (first = head) != null && removeEldestEntry(first)) { @@ -120,8 +120,12 @@ public class LinkedHashMap extends HashMap implements Map { removeNode(hash(key), key, null, false, true); } } - - // 在访问元素之后,将该元素放到双向链表的尾巴处 + // 是否删除 最近最少使用的元素 + protected boolean removeEldestEntry(Map.Entry eldest) { + return false; + } + + // 在访问元素之后,将该元素放到双向链表的尾巴处 void afterNodeAccess(Node e) { // move node to last LinkedHashMap.Entry last; if (accessOrder && (last = tail) != e) { @@ -146,14 +150,14 @@ public class LinkedHashMap extends HashMap implements Map { ++modCount; } } - + void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { for (LinkedHashMap.Entry e = head; e != null; e = e.after) { s.writeObject(e.key); s.writeObject(e.value); } } - + /** * 跟 HashMap 的构造方法没啥区别,初始容量、扩容因子 用以减少resize和rehash,提升容器整体性能 */ @@ -161,12 +165,12 @@ public class LinkedHashMap extends HashMap implements Map { super(initialCapacity, loadFactor); accessOrder = false; } - + public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } - + /** * 注意!accessOrder参数默认为false,如果想使用 LRU机制,记得设为 true */ @@ -174,13 +178,13 @@ public class LinkedHashMap extends HashMap implements Map { super(); accessOrder = false; } - + public LinkedHashMap(Map m) { super(); accessOrder = false; putMapEntries(m, false); } - + /** * 使用这个构造方法 设置accessOrder */ @@ -188,7 +192,7 @@ public class LinkedHashMap extends HashMap implements Map { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } - + /** * 是否包含指定元素 */ @@ -200,7 +204,7 @@ public class LinkedHashMap extends HashMap implements Map { } return false; } - + /** * 获取指定key对应的value,如果accessOrder为true,会回调afterNodeAccess方法 * 将元素放到队尾 @@ -213,9 +217,9 @@ public class LinkedHashMap extends HashMap implements Map { afterNodeAccess(e); return e.value; } - + /** - * {@inheritDoc} + * 根据 key 获取对应的 value,如果key不存在,则返回给定的默认值 defaultValue */ public V getOrDefault(Object key, V defaultValue) { Node e; @@ -224,8 +228,8 @@ public class LinkedHashMap extends HashMap implements Map { if (accessOrder) afterNodeAccess(e); return e.value; - } - + } + /** * {@inheritDoc} */ @@ -233,7 +237,7 @@ public class LinkedHashMap extends HashMap implements Map { super.clear(); head = tail = null; } - + /** * 获取key的set集合 */ @@ -245,7 +249,7 @@ public class LinkedHashMap extends HashMap implements Map { } return ks; } - + /** * 返回 键值对 的Set集合 */