static class Entry<K, V> extends HashMap.Node<K, V> {
//增加了节点作为链表的before和after域
Entry<K, V> before, after;
Entry(int hash, K key, V value, Node<K, V> next) {
super(hash, key, value, next);
}
}
有一个final boolean accessOrder可以在构造时指定。
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
如果accessOrder为true则get()时也会将节点移动到链尾,false时只有插入时才移到链尾,即可以按访问或者插入顺序排序。
如上图,参考之前HashMap的文章,putVal()时会调用afterNodeAccess(Node<K,V> e),LinkedHashMap重写了afterNodeAccess,处理before、after指针,将新插入的节点移至链尾。
putVal()方法里最后有一个afterNodeInsertion(boolean evict)的回调方法,该方法可能会移除最老的节点(即链首的),但是LinkedHashMap里永远不移除链首,保证行为和普通的Map一致。如果要实现LRU需要继承LinkedHashMap重写removeEldestEntry()。
LinkedHashMap实现LRU:
class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
// 缓存大小
private int capacity;
public LRULinkedHashMap(int capacity) {
// 构造时指定accessOrder为true,按get()时间排序
super(16, 0.75, true);
this.capacity = capacity;
}
@Override
public boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// 如果添加缓存,即put()后size > capacity,就会移除链表队头,即最近最少使用的缓存项
return size() > capacity;
}
}
如果put()后map的大小超过了设置的缓存大小,会移除最近最少使用的一个缓存项