前言
经常见的总是要分析下呢。 跟 List 的相似, 我们通过名称就可以出来, LinkedHashMap 是链式存储? 跟 LinkedList 一样吧。 但是通过源码的查看还是有点不同的, 我们总体看, LinkedHashMap 直接基础了 HashMap, 其内部存储数据的方式还是用的 HashMap 的那一套, 所以在数据存储的时候还是数据 + 链表/红黑树。 那么 Linked 是哪里得来的呢, 先说结果吧, 其实 LinkedHashMap 自己有一个 head 和 tail 指针, 然后在新增数据的时候会记录下新增数据的顺序。
源码分析
整体来讲就是重写了 HashMap 的方法, 然后记录下了插入的顺序等, 双向链表, 所有的操作无非就是链表的操作, 这里不再多说了。 主要分析下主要的两个流程吧。 其中一个是在新增的时候链表是怎么形成的, 第二个呢可以观察到构造方法里有一个参数是 accessOrder, 意思是会按照操作进行排序, 比如我修改了一个已经存在的值, 那么这个节点就会放到链表的结尾。
链表的形成
1 | Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { |
这个方式是重写的 HaspMap 里的方法, 其中 HashMap 是怎么处理存储数据见:HashMap 源码分析。
其中我们看下其中添加数据时的调用
1 | final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
可以看到如果我们插入的数据是新的数据, 那么会调用 newNode 去初始化一个新的 Node 节点, 所以 LinkedHashMap 中的 newNode 是新建时调用的。 多说一句, 如果已经存在了就会调用 afterNodeAccess 方法。 那么 LinkedHashMap 就是实现了这个方法从而来实现了 accessOrder 的处理的。
我们接着向下看
1 | private void linkNodeLast(LinkedHashMapEntry<K,V> p) { |
是不是很简单, 就是如果有就拼到后面, 没有就是新的链表呗。 链表操作, 不再多说。
AccessOrder 的处理
通过上面的分析我们得知, 在已存在的数据发生改变的时候会调用 afterNodeAccess, 所以我们来看看这个方法的实现。
1 | void afterNodeAccess(Node<K,V> e) { // move node to last |
其实看代码很明白了, 不再过多解释了, 就是把操作的这个节点, 放到最后。 就正如下面的这样
a(head)->b->c->d->e(tail)->null
现在修改了 c 的节点, 最后经过处理后的链表长这样
a(head)->b->d->e->c(tail)->null