LinkedHashMap
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
一、关于LinkedHashMap
LinkedHashMap继承自HashMap,具有和HashMap一样的快速查找特性。
对比与HashMap,LinkedHashMap内部维护了一个双向链表,用来维护插入顺序或者LRU顺序。迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序的。LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。
二、LinkedHashMap存储结构
1.LinkedHashMap可以认为是HashMap+LinkeList,既使用HashMap来操作数据结构,又使用LinkedList来维护插入或访问元素的先后次序。
2.内部的双向链表
/**
* The head (eldest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* The tail (youngest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> tail;
accessOrder决定了顺序,默认为false,维护的是插入顺序。当accessOrder为true时,则维护的是最近最少使用次序。也就是当accessOrder为true时,当一个节点被访问时,会将该节点移到链表的尾部,插入一个节点也是从尾部插入。
final boolean accessOrder;
afterNodeAccess()
// 当accessOrder为true时,在访问节点之后,将其移到链表的尾部
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
3. LinkedHashMap结构图
这里要注意区分next和before、After,next是用于维护HashMap指定table位置上连接的Entry的顺序的,before、After是用于维护Entry插入的先后顺序的。同时,next也是原HashMap中已有的。
根据LinkeList维护顺序的特点,在该链表中,循环双向链表的头部存放的是最久访问的节点或最先插入的节点,尾部为最近访问的或最近插入的节点,迭代器遍历方向是从链表的头部开始到链表尾部结束,在链表尾部有一个空的header节点,该节点不存放key-value内容,为LinkedHashMap类的成员属性,循环双向链表的入口。
afterNodeInsertion
在put等操作之后执行,当removeEldestEntry()方法返回true时会移动最晚的节点,也就是链表首部节点first
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
HashMap结构图:
三、利用LinkedHashMap实现LRU算法缓存
LRU是Least Recently Used的缩写,即最近最少使用。
LinkedHashMap可以实现LRU算法的缓存基于两点:
1、LinkedList首先它是一个Map,Map是基于K-V的,和缓存一致
2、LinkedList提供了一个boolean值可以让用户指定是否实现LRU
使用LinkedListHashMap实现一个LRU缓存:
设置最大缓存空间MAX_ENTRIES为3
使用LinkedListHashMap构造函数将accessOrder设置为true,开启LRU顺序。
覆盖remove1,EldestEntry()方法实现,在节点多于MAX_ENTRIES将最近最久未使用的数据移除
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private static final int MAX_ENTRIES = 3;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
LRUCache() {
super(MAX_ENTRIES, 0.75f, true);
}
}
public static void main(String[] args) {
LRUCache<Integer, String> cache = new LRUCache<>();
cache.put(1, "a");
cache.put(2, "b");
cache.put(3, "c");
cache.get(1);
cache.put(4, "d");
System.out.println(cache.keySet());
}
输出结果:[3, 1, 4]
参考博客:
https://www.cnblogs.com/xiaoxi/p/6170590.html