1、LinkedHashMap继承制HashMap,与之不同的是,LinkedHashMap重的节点LinkedEntry,双向链表来保存所有元素。。它记录了按照插入顺序排列的下一个节点和上一个节点;
/**
* LinkedEntry adds nxt/prv double-links to plain HashMapEntry.
*/
static class LinkedEntry<K, V> extends HashMapEntry<K, V> {
LinkedEntry<K, V> nxt;//下一个节点
LinkedEntry<K, V> prv;//上一个节点
/** Create the header entry */
LinkedEntry() {
super(null, null, 0, null);
nxt = prv = this;
}
/** Create a normal entry */
LinkedEntry(K key, V value, int hash, HashMapEntry<K, V> next,
LinkedEntry<K, V> nxt, LinkedEntry<K, V> prv) {
super(key, value, hash, next);
this.nxt = nxt;
this.prv = prv;
}
}
2、 LinkedHashMap返回最老的节点,LinkedEntry是一个带有头节点的链表。
public Entry<K, V> eldest() {
LinkedEntry<K, V> eldest = header.nxt;
return eldest != header ? eldest : null;
}
3、 其实,LinkedHashMap已经为我们提供了LRU算法的实现。 accessOrder用来标记 LinkedHashMap的迭代顺序,其中accessOrder为true时,按照LRU算法来访问顺序;accessOrder为false时,按照插入顺序来迭代。
/**
* True if access ordered, false if insertion ordered.
*/
private final boolean accessOrder;
@Override void addNewEntryForNullKey(V value) {
LinkedEntry<K, V> header = this.header;
// Remove eldest entry if instructed to do so.
LinkedEntry<K, V> eldest = header.nxt;
if (eldest != header && removeEldestEntry(eldest)) {
remove(eldest.key); //其中accessOrder为true时,按照LRU算法来访问顺序,删除最老的元素。但removeEldestEntry(Map.Entry<K,V> eldest)方法默认返回fasle
}
// Create new entry, link it on to list, and put it into table ,插入新元素
LinkedEntry<K, V> oldTail = header.prv;
LinkedEntry<K, V> newTail = new LinkedEntry<K,V>(
null, value, 0, null, header, oldTail);
entryForNullKey = oldTail.nxt = header.prv = newTail;
}
4、如果想要使用LinkedHashMap提供的LRU算法,则需要做两点即可:
//构造函数设置accessOrder为true
public LinkedHashMap(
int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
init();
this.accessOrder = accessOrder;
}
LinkedHashMap提供了removeEldestEntry(Map.Entry<K,V> eldest)方法,在将新条目插入到映射后,put和 putAll将调用此方法。该方法可以提供在每次添加新条目时移除最旧条目的实现程序,默认返回false,这样,此映射的行为将类似于正常映射,即永远不能移除最旧的元素。
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return false;
}
//重写此方法,维持此映射只保存MAX_SIZE个条目的稳定状态,在每次添加新条目时删除最旧的条目。
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}