HashMap 大家都清楚,底层是 数组 + (链表 / 红黑树),元素是无序的,而 LinkedHashMap 则比 HashMap 多了这一个功能,并且,LinkedHashMap 的有序可以按两种顺序排列,一种是按照插入的顺序,一种是按照访问的顺序(初始化 LinkedHashMap 对象时设置 accessOrder 参数为 true),而其内部是靠 建立一个双向链表 来维护这个顺序的,在每次插入、删除后,都会调用一个函数来进行 双向链表的维护,这也是实现 LRU Cache 功能的基础。

    先说几个比较重要的结论,大家可以根据这些结论从后面的源码解析中 得到证据。

    1. LinkedHashMap 继承了 HashMap,所以和 HashMap 的底层数据结构是一样的,都是数组+链表+红黑树,扩容机制也一样;
    2. LinkedHashMap 是通过双向链表来维护数据的,与 HashMap 的拉链式存储不一样;
    3. LinkedHashMap 存储顺序与添加顺序是一样得,同时可以根据 accessOrder 参数 来决定是否在访问时移动元素,以实现 LRU 功能。
    1. public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
    2. /**
    3. * 在 HashMap.Node节点 的基础上增加了 “前继节点” 和 “后继节点” 这种双向链表的功能特性
    4. */
    5. static class Entry<K,V> extends HashMap.Node<K,V> {
    6. Entry<K,V> before, after;
    7. Entry(int hash, K key, V value, Node<K,V> next) {
    8. super(hash, key, value, next);
    9. }
    10. }
    11. /**
    12. * 记录这个 LinkedHashMap容器的 头节点
    13. */
    14. transient LinkedHashMap.Entry<K,V> head;
    15. /**
    16. * 记录这个 LinkedHashMap容器的 尾节点
    17. */
    18. transient LinkedHashMap.Entry<K,V> tail;
    19. /**
    20. * 是否根据访问 进行排序,true为是,可通过构造方法进行设置
    21. */
    22. final boolean accessOrder;
    23. // 下面是一些私有的内部公用方法
    24. // 将元素连接到链表尾部
    25. private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    26. LinkedHashMap.Entry<K,V> last = tail;
    27. tail = p;
    28. if (last == null)
    29. head = p;
    30. else {
    31. p.before = last;
    32. last.after = p;
    33. }
    34. }
    35. // apply src's links to dst
    36. private void transferLinks(LinkedHashMap.Entry<K,V> src, LinkedHashMap.Entry<K,V> dst) {
    37. LinkedHashMap.Entry<K,V> b = dst.before = src.before;
    38. LinkedHashMap.Entry<K,V> a = dst.after = src.after;
    39. if (b == null)
    40. head = dst;
    41. else
    42. b.after = dst;
    43. if (a == null)
    44. tail = dst;
    45. else
    46. a.before = dst;
    47. }
    48. // 下面是一些 重写的 HashMap 的 hook methods,其中 afterNodeInsertion、afterNodeRemoval
    49. // afterNodeAccess及方法,在每次插入、删除、访问后,都会回调 用来维护双向链表
    50. void reinitialize() {
    51. super.reinitialize();
    52. head = tail = null;
    53. }
    54. Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    55. LinkedHashMap.Entry<K,V> p =
    56. new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    57. linkNodeLast(p);
    58. return p;
    59. }
    60. Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
    61. LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
    62. LinkedHashMap.Entry<K,V> t =
    63. new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
    64. transferLinks(q, t);
    65. return t;
    66. }
    67. TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
    68. TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
    69. linkNodeLast(p);
    70. return p;
    71. }
    72. TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
    73. LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
    74. TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
    75. transferLinks(q, t);
    76. return t;
    77. }
    78. // 在删除元素之后,将元素从双向链表中删除
    79. void afterNodeRemoval(Node<K,V> e) { // unlink
    80. LinkedHashMap.Entry<K,V> p =
    81. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    82. p.before = p.after = null;
    83. if (b == null)
    84. head = a;
    85. else
    86. b.after = a;
    87. if (a == null)
    88. tail = b;
    89. else
    90. a.before = b;
    91. }
    92. // 可用于删除最老的元素
    93. void afterNodeInsertion(boolean evict) { // possibly remove eldest
    94. LinkedHashMap.Entry<K,V> first;
    95. if (evict && (first = head) != null && removeEldestEntry(first)) {
    96. K key = first.key;
    97. removeNode(hash(key), key, null, false, true);
    98. }
    99. }
    100. // 是否删除 最近最少使用的元素
    101. protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    102. return false;
    103. }
    104. // 在访问元素之后,将该元素放到双向链表的尾巴处
    105. void afterNodeAccess(Node<K,V> e) { // move node to last
    106. LinkedHashMap.Entry<K,V> last;
    107. if (accessOrder && (last = tail) != e) {
    108. LinkedHashMap.Entry<K,V> p =
    109. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    110. p.after = null;
    111. if (b == null)
    112. head = a;
    113. else
    114. b.after = a;
    115. if (a != null)
    116. a.before = b;
    117. else
    118. last = b;
    119. if (last == null)
    120. head = p;
    121. else {
    122. p.before = last;
    123. last.after = p;
    124. }
    125. tail = p;
    126. ++modCount;
    127. }
    128. }
    129. void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
    130. for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
    131. s.writeObject(e.key);
    132. s.writeObject(e.value);
    133. }
    134. }
    135. /**
    136. * 跟 HashMap 的构造方法没啥区别,初始容量、扩容因子 用以减少resize和rehash,提升容器整体性能
    137. */
    138. public LinkedHashMap(int initialCapacity, float loadFactor) {
    139. super(initialCapacity, loadFactor);
    140. accessOrder = false;
    141. }
    142. public LinkedHashMap(int initialCapacity) {
    143. super(initialCapacity);
    144. accessOrder = false;
    145. }
    146. /**
    147. * 注意!accessOrder参数默认为false,如果想使用 LRU机制,记得设为 true
    148. */
    149. public LinkedHashMap() {
    150. super();
    151. accessOrder = false;
    152. }
    153. public LinkedHashMap(Map<? extends K, ? extends V> m) {
    154. super();
    155. accessOrder = false;
    156. putMapEntries(m, false);
    157. }
    158. /**
    159. * 使用这个构造方法 设置accessOrder
    160. */
    161. public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
    162. super(initialCapacity, loadFactor);
    163. this.accessOrder = accessOrder;
    164. }
    165. /**
    166. * 是否包含指定元素
    167. */
    168. public boolean containsValue(Object value) {
    169. for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
    170. V v = e.value;
    171. if (v == value || (value != null && value.equals(v)))
    172. return true;
    173. }
    174. return false;
    175. }
    176. /**
    177. * 获取指定key对应的value,如果accessOrder为true,会回调afterNodeAccess方法
    178. * 将元素放到队尾
    179. */
    180. public V get(Object key) {
    181. Node<K,V> e;
    182. if ((e = getNode(hash(key), key)) == null)
    183. return null;
    184. if (accessOrder)
    185. afterNodeAccess(e);
    186. return e.value;
    187. }
    188. /**
    189. * 根据 key 获取对应的 value,如果key不存在,则返回给定的默认值 defaultValue
    190. */
    191. public V getOrDefault(Object key, V defaultValue) {
    192. Node<K,V> e;
    193. if ((e = getNode(hash(key), key)) == null)
    194. return defaultValue;
    195. if (accessOrder)
    196. afterNodeAccess(e);
    197. return e.value;
    198. }
    199. /**
    200. * {@inheritDoc}
    201. */
    202. public void clear() {
    203. super.clear();
    204. head = tail = null;
    205. }
    206. /**
    207. * 获取key的set集合
    208. */
    209. public Set<K> keySet() {
    210. Set<K> ks = keySet;
    211. if (ks == null) {
    212. ks = new LinkedKeySet();
    213. keySet = ks;
    214. }
    215. return ks;
    216. }
    217. /**
    218. * 返回 键值对 的Set集合
    219. */
    220. public Set<Map.Entry<K,V>> entrySet() {
    221. Set<Map.Entry<K,V>> es;
    222. return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    223. }
    224. }