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的實現。