今天来分析一下JDK LinkedHashMap的源代码
- public class LinkedHashMap<K,V>
- extends HashMap<K,V>
- implements Map<K,V>
可以看到,LinkedHashMap继承自HashMap,并且也实现了Map接口,所以LinkedHashMap沿用了HashMap的大多数方法
,包括构造方法也调用了父类HashMap的构造方法:
- public LinkedHashMap(int initialCapacity, float loadFactor) {
- super(initialCapacity, loadFactor);
- accessOrder = false;
- }
- public LinkedHashMap(int initialCapacity) {
- super(initialCapacity);
- accessOrder = false;
- }
- public LinkedHashMap() {
- super();
- accessOrder = false;
- }
- public LinkedHashMap(Map<? extends K, ? extends V> m) {
- super(m);
- accessOrder = false;
- }
- public LinkedHashMap(int initialCapacity,
- float loadFactor,
- boolean accessOrder) {
- super(initialCapacity, loadFactor);
- this.accessOrder = accessOrder;
- }
但是昨天在分析HashMap的时候说过HashMap的init方法没有实现,但是LinkedHaqshMap已经对其实现:
- void init() {
- header = new Entry<K,V>(-1, null, null, null);//初始化一个Entry类型的header
- header.before = header.after = header;
- }
在LinkedHashMap中多了一个accessOrder变量,他表示迭代时候的一个顺序,若为true,则按照读取顺序排序(读得越多在链表的越后面,读得越少在链表的越前面,LRU,最近最少使用),若为false则按照插入顺序排序.从LinkedHaqshMap的前4个构造方法可以看出,accessOrder默认为false,故按照插入顺序进行排序.
- 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;
- }
getEntry()HashMap里的实现:
- 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;
}
在这个get方法中要注意recordAccess这个方法:
- void recordAccess(HashMap<K,V> m) {
- LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
- if (lm.accessOrder) {
- lm.modCount++;
- remove();
- addBefore(lm.header);
- }
- }
这个方法定义在LinkedHashMap的内部类Entry中,他判断accessOrder属性,若为true,则执行一个叫做LRU的算法
该算法的中文名称叫做最近最少使用算法,他通过将刚访问的entry移除,然后加到header前面,这样迭代的时候会优先迭代
最近频繁访问的entry,从而就改变了迭代的顺序
对于put方法,LinkedHashMap也实现了父类HashMap没有实现的recordAccess,并重写了addEntry方法,虽然在LinkedHashMap没有重写put方法
- void addEntry(int hash, K key, V value, int bucketIndex) {
- createEntry(hash, key, value, bucketIndex);//在header前构造一个entry
- Entry<K,V> eldest = header.after;//找到最老的一个元素
- if (removeEldestEntry(eldest)) {
- removeEntryForKey(eldest.key);
- } else {
- if (size >= threshold)
- resize(2 * table.length);
- }
- }
可以看到该方法会删除最老的一个元素,removeEldestEntry是一个受保护的方法,用来确定是否满足删除条件,可以重写它实现自己的策略,默认该方法返回false
当然,可以通过覆盖该方法,加入一定的条件,如果条件满足则返回true.如:
protected boolean removeEldestEntry(Map.Entry eldest) {