標籤:
HashMap使用雜湊表來儲存資料,並用拉鏈法來處理衝突。LinkedHashMap繼承自HashMap,同時自身有一個鏈表,使用鏈表格儲存體資料,不存在衝突。
LinkedList和LinkedHashMap一樣使用一個雙向迴圈鏈表,但LinkedList儲存的是簡單的資料,並不是“索引值對”。
LinkedList和LinkedHashMap都可以維護內容的順序,但HashMap不維護順序。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
HashMap的init方法沒有實現,但是LinkedHaqshMap已經對其實現:
void init() { //初始化一個Entry類型的header header = new Entry<K,V>(-1, null, null, null); header.before = header.after = header; }
在LinkedHashMap中多了一個accessOrder變數,他表示迭代時候的一個順序,若為true,則按照讀取順序排序(讀得越多在鏈表的越後面,讀得越少在鏈表的越前面,LRU,最近最少使用),若為false則按照插入順序排序.從LinkedHaqshMap的前4個構造方法可以看出,accessOrder預設為false,故按照插入順序進行排序。
void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } }
在LRU演算法中,最少使用的頁面被先換出,最近使用的很可能以後還會使用。
他判斷accessOrder屬性,若為true,則執行一個叫做LRU的演算法,將剛訪問的entry移除,然後加到header前面,這樣迭代的時候會優先迭代最近頻繁訪問的entry(不是鏈表頭),從而就改變了迭代的順序。
void addEntry(int hash, K key, V value, int bucketIndex) { createEntry(hash, key, value, bucketIndex); Entry<K,V> eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } else { if (size >= threshold) resize(2 * table.length); } }
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { //始終返回的是false
return false; }
啟發:若希望將Map當做Cache來使用,並且限制大小,只需繼承LinkedHashMap並重寫removeEldestEntry(Entry<K,V> eldest)方法,像這樣:
private static final int MAX_ENTRIES = 100; protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; }
實現最近被使用(LRU)緩衝:
import java.util.LinkedHashMap;import java.util.Map; public LRUCache<K, V> extends LinkedHashMap<K, V> { private int cacheSize; public LRUCache(int cacheSize) { super(16, 0.75, true);//排序策略 this.cacheSize = cacheSize; }
Java集合(13)--LinkedHashMap源碼分析