LinkedHashMap 是一个有序集合,默认是按插入顺序进行排序,也支持按照最近访问的数据在最后面(accessOrder=true)
LinkedHashMap 继承了 HashMap ,在Entry中继承了HashMap的Node 内部类,并新增加before 和 after,使得有序。
LinkedHashMap 并没有实现 HashMap 的put方法,而是在putVal 方法中,执行newNode 时,重写了newNode方法。
主要代码
// 继承了HashMap.Node 内部类,并新增了before 和 after 节点
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);
}
}
// 按照存储的顺序
public LinkedHashMap() {
super();
accessOrder = false;
}
// accessOrder 如果是true ,则将最新访问的元素放到最后面。
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
// ......
if ((p = tab[i = (n - 1) & hash]) == null)
// 当是LinkedHashMap时 ,执行LinkedHashMap重写的方法
tab[i] = newNode(hash, key, value, null);
else {
// ......
}
// ......
// HashMap 没有实现
// 对LinkedHashMap 有用,用来回调移除最早放入Map的对象
afterNodeInsertion(evict);
return null;
}
// LinkedHashMap 使用的是HashMap的模板方法,
// 只是此处的数组节点是继承了HashMap.Entry ,进行增加了before 和after ,从而实现有序
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
// LinkedHashMap中被覆盖的afterNodeInsertion方法,用来回调移除最早放入Map的对象
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
基于 LinkedHashMap 实现 LRU 淘汰策略
package com.guaoran.interview.in2018.collection.map;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Author gucheng
* @Description
* 重写 {@link LinkedHashMap#removeEldestEntry(Map.Entry)} 来实现 LRU 淘汰策略
* 2019-03-18 9:30
*/
public class LinkedHashMapLRU<K,V> extends LinkedHashMap<K,V> {
private int initialCapacity;
public LinkedHashMapLRU(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
this.initialCapacity = initialCapacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
if(size() > this.initialCapacity){
System.out.println(eldest + "删除了");
return true;
}
return false;
}
public static void main(String[] args) {
Map<String,Integer> sortMapLRU = new LinkedHashMapLRU<String,Integer>(16,0.75f);
for (int i = 0; i < 10; i++) {
sortMapLRU.put("key"+i,i);
}
sortMapLRU.entrySet().forEach(m ->{
System.out.println(m.getKey()+" -> "+m.getValue());
});
System.out.println(sortMapLRU.get("key9"));
System.out.println(sortMapLRU.get("key5"));
System.out.println(sortMapLRU.get("key3"));
sortMapLRU.entrySet().forEach(m ->{
System.out.println(m.getKey()+" -> "+m.getValue());
});
System.out.println("LRU.....................start");
for (int i = 10; i < 20; i++) {
sortMapLRU.put("key"+i,i);
}
sortMapLRU.entrySet().forEach(m ->{
System.out.println(m.getKey()+" -> "+m.getValue());
});
}
}