1 public class LinkedHashMap<K,V> 2 extends HashMap<K,V> 3 implements Map<K,V>
1 /** 2 * The head of the doubly linked list. 3 */ 4 private transient Entry<K,V> header ; 5 6 /** 7 * The iteration ordering method for this linked hash map: <tt>true</tt> 8 * for access -order, <tt> false</tt> for insertion -order. 9 * 10 * @serial 11 */ 12 private final boolean accessOrder;
1 /** 2 * LinkedHashMap entry. 3 */ 4 private static class Entry<K,V> extends HashMap.Entry<K,V> { 5 // These fields comprise the doubly linked list used for iteration. 6 // 雙向鏈表的上一個節點before和下一個節點after 7 Entry<K,V> before, after ; 8 9 // 構造方法直接調用父類HashMap的構造方法(super) 10 Entry( int hash, K key, V value, HashMap.Entry<K,V> next) { 11 super(hash, key, value, next); 12 } 13 14 /** 15 * 從鏈表中刪除當前節點的方法 16 */ 17 private void remove() { 18 // 改變當前節點先後兩個節點的引用關係,當前節點沒有被引用後,gc能夠回收 19 // 將上一個節點的after指向下一個節點 20 before.after = after; 21 // 將下一個節點的before指向前一個節點 22 after.before = before; 23 } 24 25 /** 26 * 在指定的節點前加入一個節點到鏈表中(也就是加入到鏈表尾部) 27 */ 28 private void addBefore(Entry<K,V> existingEntry) { 29 // 下面改變本身對先後的指向 30 // 將當前節點的after指向給定的節點(加入到existingEntry前面嘛) 31 after = existingEntry; 32 // 將當前節點的before指向給定節點的上一個節點 33 before = existingEntry.before ; 34 35 // 下面改變先後最本身的指向 36 // 上一個節點的after指向本身 37 before.after = this; 38 // 下一個幾點的before指向本身 39 after.before = this; 40 } 41 42 // 當向Map中獲取查詢元素或修改元素(put相同key)的時候調用這個方法 43 void recordAccess(HashMap<K,V> m) { 44 LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; 45 // 若是accessOrder爲true,也就是使用最近較少使用順序 46 if (lm.accessOrder ) { 47 lm. modCount++; 48 // 先刪除,再添加,也就至關於移動了 49 // 刪除當前元素 50 remove(); 51 // 將當前元素加入到header前(也就是鏈表尾部) 52 addBefore(lm. header); 53 } 54 } 55 56 // 當從Map中刪除元素的時候調動這個方法 57 void recordRemoval(HashMap<K,V> m) { 58 remove(); 59 } 60 }
能夠看到Entry繼承了HashMap中的Entry,可是LinkedHashMap中的Entry多了兩個屬性指向上一個節點的before和指向下一個節點的after,也正是這兩個屬性組成了一個雙向鏈表。等等。。。Entry還有一個繼承下來的next屬性,這個next是單向鏈表中用來指向下一個節點的,怎麼回事嘛,怎麼又是單向鏈表又是雙向鏈表呢,都要暈了對不對,其實想的沒錯,這裏的節點便是Hash表中的單向鏈表中的一個節點,它又是LinkedHashMap維護的雙向鏈表中的一個節點,是否是瞬間以爲高大上了。圖解一下吧(不要告訴我圖好亂,我看不懂。。。)html
1 /** 2 * 構造一個指定初始容量和加載因子的LinkedHashMap,默認accessOrder爲false 3 */ 4 public LinkedHashMap( int initialCapacity, float loadFactor) { 5 super(initialCapacity, loadFactor); 6 accessOrder = false; 7 } 8 9 /** 10 * 構造一個指定初始容量的LinkedHashMap,默認accessOrder爲false 11 */ 12 public LinkedHashMap( int initialCapacity) { 13 super(initialCapacity); 14 accessOrder = false; 15 } 16 17 /** 18 * 構造一個使用默認初始容量(16)和默認加載因子(0.75)的LinkedHashMap,默認accessOrder爲false 19 */ 20 public LinkedHashMap() { 21 super(); 22 accessOrder = false; 23 } 24 25 /** 26 * 構造一個指定map的LinkedHashMap,所建立LinkedHashMap使用默認加載因子(0.75)和足以容納指定map的初始容量,默認accessOrder爲false 。 27 */ 28 public LinkedHashMap(Map<? extends K, ? extends V> m) { 29 super(m); 30 accessOrder = false; 31 } 32 33 /** 34 * 構造一個指定初始容量、加載因子和accessOrder的LinkedHashMap 35 */ 36 public LinkedHashMap( int initialCapacity, 37 float loadFactor, 38 boolean accessOrder) { 39 super(initialCapacity, loadFactor); 40 this.accessOrder = accessOrder; 41 }
1 /** 2 * Constructs an empty <tt>HashMap</tt> with the specified initial 3 * capacity and load factor. 4 * 5 * @param initialCapacity the initial capacity 6 * @param loadFactor the load factor 7 * @throws IllegalArgumentException if the initial capacity is negative 8 * or the load factor is nonpositive 9 */ 10 public HashMap( int initialCapacity, float loadFactor) { 11 if (initialCapacity < 0) 12 throw new IllegalArgumentException( "Illegal initial capacity: " + 13 initialCapacity); 14 if (initialCapacity > MAXIMUM_CAPACITY) 15 initialCapacity = MAXIMUM_CAPACITY; 16 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 17 throw new IllegalArgumentException( "Illegal load factor: " + 18 loadFactor); 19 20 // Find a power of 2 >= initialCapacity 21 int capacity = 1; 22 while (capacity < initialCapacity) 23 capacity <<= 1; 24 25 this.loadFactor = loadFactor; 26 threshold = (int)(capacity * loadFactor); 27 table = new Entry[capacity]; 28 init(); 29 } 30 31 /** 32 * Initialization hook for subclasses. This method is called 33 * in all constructors and pseudo -constructors (clone, readObject) 34 * after HashMap has been initialized but before any entries have 35 * been inserted. (In the absence of this method, readObject would 36 * require explicit knowledge of subclasses.) 37 */ 38 void init() { 39
哦,明白了,init()在HashMap中是一個空方法,也就是給子類留的一個回調函數,ok,咱們來看下LinkedHashMap對init()方法的實現吧。java
1 /** 2 * Called by superclass constructors and pseudoconstructors (clone, 3 * readObject) before any entries are inserted into the map. Initializes 4 * the chain. 5 */ 6 void init() { 7 // 初始化話header,將hash設置爲-1,key、value、next設置爲null 8 header = new Entry<K,V>(-1, null, null, null); 9 // header的before和after都指向header自身 10 header.before = header. after = header ; 11
1 /** 2 * This override alters behavior of superclass put method. It causes newly 3 * allocated entry to get inserted at the end of the linked list and 4 * removes the eldest entry if appropriate. 5 */ 6 void addEntry( int hash, K key, V value, int bucketIndex) { 7 // 調用createEntry方法建立一個新的節點 8 createEntry(hash, key, value, bucketIndex); 9 10 // Remove eldest entry if instructed, else grow capacity if appropriate 11 // 取出header後的第一個節點(由於header不保存數據,因此取header後的第一個節點) 12 Entry<K,V> eldest = header.after ; 13 // 判斷是容量不夠了是要刪除第一個節點仍是須要擴容 14 if (removeEldestEntry(eldest)) { 15 // 刪除第一個節點(可實現FIFO、LRU策略的Cache) 16 removeEntryForKey(eldest. key); 17 } else { 18 // 和HashMap同樣進行擴容 19 if (size >= threshold) 20 resize(2 * table.length ); 21 } 22 } 23 24 /** 25 * This override differs from addEntry in that it doesn't resize the 26 * table or remove the eldest entry. 27 */ 28 void createEntry( int hash, K key, V value, int bucketIndex) { 29 // 下面三行代碼的邏輯是,建立一個新節點放到單向鏈表的頭部 30 // 取出數組bucketIndex位置的舊節點 31 HashMap.Entry<K,V> old = table[bucketIndex]; 32 // 建立一個新的節點,並將next指向舊節點 33 Entry<K,V> e = new Entry<K,V>(hash, key, value, old); 34 // 將新建立的節點放到數組的bucketIndex位置 35 table[bucketIndex] = e; 36 37 // 維護雙向鏈表,將新節點添加在雙向鏈表header前面(鏈表尾部) 38 e.addBefore( header); 39 // 計數器size加1 40 size++; 41 } 42 43 /** 44 * 默認返回false,也就是不會進行元素刪除了。若是想實現cache功能,只需重寫該方法 45 */ 46 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { 47 return false; 48 }
1 public V get(Object key) { 2 Entry<K,V> e = (Entry<K,V>)getEntry(key); 3 if (e == null) 4 return null; 5 e.recordAccess( this); 6 return e.value ; 7 }
1 /** 2 * Returns <tt>true</tt> if this map maps one or more keys to the 3 * specified value. 4 * 5 * @param value value whose presence in this map is to be tested 6 * @return <tt> true</tt> if this map maps one or more keys to the 7 * specified value 8 */ 9 public boolean containsValue(Object value) { 10 // Overridden to take advantage of faster iterator 11 // 遍歷雙向鏈表,查找指定的value 12 if (value==null) { 13 for (Entry e = header .after; e != header; e = e.after ) 14 if (e.value ==null) 15 return true; 16 } else { 17 for (Entry e = header .after; e != header; e = e.after ) 18 if (value.equals(e.value )) 19 return true; 20 } 21 return false; 22 }
1 import java.util.LinkedHashMap; 2 import java.util.Map; 3 4 public class MyLocalCache extends LinkedHashMap<String, Object> { 5 6 private static final long serialVersionUID = 7182816356402068265L; 7 8 private static final int DEFAULT_MAX_CAPACITY = 1024; 9 10 private static final float DEFAULT_LOAD_FACTOR = 0.75f; 11 12 private int maxCapacity; 13 14 public enum Policy { 15 FIFO, LRU 16 } 17 18 public MyLocalCache(Policy policy) { 19 super(DEFAULT_MAX_CAPACITY, DEFAULT_LOAD_FACTOR, Policy.LRU .equals(policy)); 20 this.maxCapacity = DEFAULT_MAX_CAPACITY; 21 } 22 23 public MyLocalCache(int capacity, Policy policy) { 24 super(capacity, DEFAULT_LOAD_FACTOR, Policy. LRU.equals(policy)); 25 this.maxCapacity = capacity; 26 } 27 28 @Override 29 protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) { 30 return this.size() > maxCapacity; 31 } 32 33 public static void main(String[] args) { 34 MyLocalCache cache = new MyLocalCache(5, Policy.LRU); 35 cache.put( "k1", "v1" ); 36 cache.put( "k2", "v2" ); 37 cache.put( "k3", "v3" ); 38 cache.put( "k4", "v4" ); 39 cache.put( "k5", "v5" ); 40 cache.put( "k6", "v6" ); 41 42 System. out.println("size=" + cache.size()); 43 44 System. out.println("----------------------" ); 45 for (Map.Entry<String, Object> entry : cache.entrySet()) { 46 System. out.println(entry.getValue()); 47 } 48 49 System. out.println("----------------------" ); 50 51 System. out.println("k3=" + cache.get("k3")); 52 53 System. out.println("----------------------" ); 54 for (Map.Entry<String, Object> entry : cache.entrySet()) { 55 System. out.println(entry.getValue()); 56 } 57 } 58 59 }
參見:算法