LinkedHashMap特别有意思,它不单单是在HashMap上增长Entry的双向连接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式建立LinkedHashMap)或者实现LRU(Least Recently Used最近最少算法,以access模式建立LinkedHashMap)。算法
下面是LinkedHashMap的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; }
其中有一段:e.recordAccess(this)。下面咱们进入Entry的定义性能
void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } }
这里的addBefore(lm.header)是作什么呢?再看this
private void addBefore(Entry<K,V> existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; }
从这里能够看到了,addBefore(lm.header)是把当前访问的元素挪到head的前面,即最近访问的元素被放到了链表头,如此要实现LRU算法只须要从链表末尾往前删除就能够了,多么巧妙的方法。spa
在看到LinkedHashMap以前,我觉得实现LRU算法是在每一个元素内部维护一个计数器,访问一次自增一次,计数器最小的会被移除。可是要想到,每次add的时候都须要作这么一次遍历循环,并取出最小的抛弃,在HashMap较大的时候效率不好。固然也有其余方法来改进,好比创建<访问次数,LinkedHashMap元素的key>这样的TreeMap,在add的时候往TreeMap里也插入一份,删除的时候取最小的便可,改进了效率但没有LinkedHashMap内部的默认实现来的简捷。code
LinkedHashMap是何时删除的呢?对象
void addEntry(int hash, K key, V value, int bucketIndex) { super.addEntry(hash, key, value, bucketIndex); // Remove eldest entry if instructed Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } }
在增长Entry的时候,经过removeEldestEntry(eldest)判断是否须要删除最老的Entry,若是须要则remove。注意看这里Entry<K,V> eldest=header.after,记得咱们前面提过LinkedHashMap还维护一个双向链表,这里的header.after就是链表尾部最后一个元素(头部元素是head.before)。blog
LinkedHashMap默认的removeEldestEntry方法以下排序
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; }
keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) { private static final long serialVersionUID = 4267176411845948333L; protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) { boolean tooBig = size() > size; if (tooBig) { eldestKey = eldest.getKey(); } return tooBig; } };
开发者的子类并不须要直接操做eldest(上例中得到eldestKey只是MyBatis须要映射到Cache对象中的元素),只要根据本身的条件(通常是元素个数是否到达阈值)返回true/false便可。注意,要按照LRU排序必须在new LinkedHashMap()的构造函数的最后一个参数传入true(true表明LinkedHashMap内部的双向链表按访问顺序排序,false表明按插入顺序排序)。继承
在LinkedHashMap的注释里明确提到,该类在保持插入顺序、不想HashMap那样混乱的状况下,又没有像TreeMap那样的性能损耗。同时又可以很巧妙地实现LRU算法。其余方面和HashMap功能一致。有兴趣的同窗能够仔细看看LinkedHashMap的实现。