一. 概述:
LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。LinkedHashMap实现与HashMap的不同之处在于,LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序(insert-order)或者是访问顺序,其中默认的迭代访问顺序就是插入顺序,即可以按插入的顺序遍历元素,这点和HashMap有很大的不同。
二.LinkedHashMap的accessOrder
1.访问顺序
LinkedHashMap除了支持默认的插入顺序,还支持访问顺序。所谓访问顺序(access-order)是指在迭代遍历列表中的元素时最近访问的元素会排在LinkedHashMap的尾部 。从其构造函数中可以看出当accessOrder设为true时即为访问顺序。
java代码 ,继承的HashMap的get方法
public V get(Object key) {
Entry<K,V> e = (Entry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
HashMap的 getEntry()方法
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
java代码,recordAccess()
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header); //将元素m放到链表的末尾
}
}
java代码,addBefore()
/**
* Inserts this entry before the specified existing entry in the list.
*/
private void addBefore(Entry<K,V> existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
2.访问顺序时程序举例
输出如下:
通过例子可以看出,最近经常使用的元素就放在后面,最近最少使用的就排在了链表的前面。
三.LinkedHashMap的扩展应用
基于LinkedHashMap的访问顺序的特点,可构造一个LRU(Least Recently Used)最近最少使用简单缓存。也有一些开源的缓存产品如ehcache的淘汰策略(LRU)就是在LinkedHashMap上扩展的。
1.LruCache的简单代码
2.测试代码
输出如下:
四.LinkedHashMap对上述特性支持的分析
1.添加时删除最老元素
LinkedHashMap如何在添加元素时把最早放入的元素删除的呢,LinkedHashMap没有提供put方法,而是使用基类HashMap的put方法,看下面的HashMap的put(K key, V value)方法的源代码:
LinkedHashMap覆盖了HashMap中的这个addEntry(hash, key, value, i)方法,在 LinkedHashMap类中,removeEldestEntry()永远返回false;
也就是这个方法,提供了子类更强大功能扩展的机会。
2.访问时重组列表
在获取元素时,LinkedHashMap提供了get()方法,其代码如下:
HashMap中这个recordAccess()方法没有实现,只有空的方法体,在LinkedHashMap中的实现如下 ,也就是这个方法,将最近访问的元素给予重组,达到了LRU的目的。