LinkedHashMap 源码
LinkedHashMap 是一个哈希表,拥有可预测的迭代顺序。与 HashMap 不同点在于使用了一个双向链表来维护所有的 Entry,双向链表定义了哈希表的迭代顺序。
一个参数
LinkedHashMap 的迭代顺序有两种:节点插入顺序和节点访问顺序。可通过在构造方法中传递 boolean accessOrder来指定——当 accessOrder 为 false 时,迭代顺序为节点插入顺序;当 accessOrder 为 true 时,迭代顺序为节点访问顺序。
节点类型
继承了 HashMap 的 Node 类,并增加了前后指针,以便构造双向链表。
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}节点创建
在 HashMap 中,创建节点是通过 newNode 方法:
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
return new Node<>(hash, key, value, next);
}而 LinkedHashMap 通过重写 HashMap 的 newNode 方法,创建Entry实例:
更新迭代顺序的时机
在 HashMap 中,定义了如下三个方法:
通过注释可以看出是专门为 LinkedHashMap 进行后续行为而定义的。
afterNodeAccess 是节点被访问后调用,在 HashMap 中,这个方法只在更新旧节点的值时被调用了,在get方法内并没有被调用,因此 LinkedHashMap 重写了 get方法,当需要根据访问顺序迭代时,调用afterNodeAccess 调整:
afterNodeInsertion 处理新增节点后行为,在 HashMap 中的 putVal方法中最后就调用了这个方法,但是 afterNodeInsertion 只处理了新节点添加之后的顺序更新,比如如果需要删除头节点,则在此时进行删除调整;而对于新创建的节点,更新迭代顺序是在linkNodeLast方法中,如上面代码所示,这个方法是在newNode方法中被调用的。
afterNodeRemoval 在 HashMap 中的removeNode方法中调用。
综上,LinkedHashMap 更新迭代顺序链表的时机为:
时机
调用方法
插入新节点时
linkNodeLast
插入新节点后(处理删除头节点)
afterNodeInsertion
更新旧节点
afterNodeAccess
删除节点
afterNodeRemoval
访问节点
afterNodeAccess
调整顺序的源码实现
linkNodeLast
linkNodeLastlinkNodeLast 的作用就是将新创建的节点放置于链表尾部,其源码如下:
afterNodeInsertion
afterNodeInsertionevict 标识 HashMap 是否处于创建中,evict 为 false 的情况主要包括在构造方法中、clone、readFromObject等方法中调用 put 相关操作时,其他情况一律为 true。
可以看出 afterNodeInsertion 主要是根据需要(removeEldestEntry 方法返回值)移除头结点,然后在移除后会有调整顺序的操作,不过已经是在afterNodeRemoval方法中了。 (removeNode 会调用 afterNodeRemoval)
afterNodeRemoval
afterNodeRemovalafterNodeRemoval 的作用很简单,处理了节点删除后的链表维护。
afterNodeAccess
afterNodeAccessafterNodeAccess 方法在 accessOrder为true时,将被访问的节点移到链表尾部。
其他优化
containsValue()
LinkedHashMap 直接从头遍历双向链表查找, HashMap 遍历数组同时还要遍历每个桶内的链表,效率比LinkedHashMap 低。
总结
LinkedHashMap 是一个拥有可预测迭代顺序的哈希表,它继承自 HashMap,并用一个双向链表来维护所有 entry 的顺序,默认迭代顺序是按节点插入顺序,可以通过将accessOrder设为true将迭代顺序指定为节点访问顺序。当节点被添加、修改、访问和删除时,通过调用对应的方法来调整节点在双向链表中的顺序,从而达到维护访问顺序的目的。
最后更新于
这有帮助吗?