日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

转:【Java集合源码剖析】LinkedHashmap源码剖析

發布時間:2024/4/17 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转:【Java集合源码剖析】LinkedHashmap源码剖析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處:http://blog.csdn.net/ns_code/article/details/37867985

?

? ? 前言:有網友建議分析下LinkedHashMap的源碼,于是花了一晚上時間研究了下,分享出此文(這個系列的最后一篇博文了),希望大家相互學習。LinkedHashMap的源碼理解起來也不難(當然,要建立在對HashMap源碼有較好理解的基礎上)。

? ? LinkedHashMap簡介

? ? LinkedHashMap是HashMap的子類,與HashMap有著同樣的存儲結構,但它加入了一個雙向鏈表的頭結點,將所有put到LinkedHashmap的節點一一串成了一個雙向循環鏈表,因此它保留了節點插入的順序,可以使節點的輸出順序與輸入順序相同。

? ? LinkedHashMap可以用來實現LRU算法(這會在下面的源碼中進行分析)。

? ? LinkedHashMap同樣是非線程安全的,只在單線程環境下使用。

?

? ? LinkedHashMap源碼剖析

? ? LinkedHashMap源碼如下(加入了詳細的注釋):

[java] view plaincopy
  • package?java.util;??
  • import?java.io.*;??
  • ??
  • ??
  • public?class?LinkedHashMap<K,V>??
  • ????extends?HashMap<K,V>??
  • ????implements?Map<K,V>??
  • {??
  • ??
  • ????private?static?final?long?serialVersionUID?=?3801124242820219131L;??
  • ??
  • ????//雙向循環鏈表的頭結點,整個LinkedHa只喲shMap中只有一個header,??
  • ????//它將哈希表中所有的Entry貫穿起來,header中不保存key-value對,只保存前后節點的引用??
  • ????private?transient?Entry<K,V>?header;??
  • ??
  • ????//雙向鏈表中元素排序規則的標志位。??
  • ????//accessOrder為false,表示按插入順序排序??
  • ????//accessOrder為true,表示按訪問順序排序??
  • ????private?final?boolean?accessOrder;??
  • ??
  • ????//調用HashMap的構造方法來構造底層的數組??
  • ????public?LinkedHashMap(int?initialCapacity,?float?loadFactor)?{??
  • ????????super(initialCapacity,?loadFactor);??
  • ????????accessOrder?=?false;????//鏈表中的元素默認按照插入順序排序??
  • ????}??
  • ??
  • ????//加載因子取默認的0.75f??
  • ????public?LinkedHashMap(int?initialCapacity)?{??
  • ????????super(initialCapacity);??
  • ????????accessOrder?=?false;??
  • ????}??
  • ??
  • ????//加載因子取默認的0.75f,容量取默認的16??
  • ????public?LinkedHashMap()?{??
  • ????????super();??
  • ????????accessOrder?=?false;??
  • ????}??
  • ??
  • ????//含有子Map的構造方法,同樣調用HashMap的對應的構造方法??
  • ????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;??
  • ????}??
  • ??
  • ????//覆寫父類的init()方法(HashMap中的init方法為空),??
  • ????//該方法在父類的構造方法和Clone、readObject中在插入元素前被調用,??
  • ????//初始化一個空的雙向循環鏈表,頭結點中不保存數據,頭結點的下一個節點才開始保存數據。??
  • ????void?init()?{??
  • ????????header?=?new?Entry<K,V>(-1,?null,?null,?null);??
  • ????????header.before?=?header.after?=?header;??
  • ????}??
  • ??
  • ??
  • ????//覆寫HashMap中的transfer方法,它在父類的resize方法中被調用,??
  • ????//擴容后,將key-value對重新映射到新的newTable中??
  • ????//覆寫該方法的目的是為了提高復制的效率,??
  • ????//這里充分利用雙向循環鏈表的特點進行迭代,不用對底層的數組進行for循環。??
  • ????void?transfer(HashMap.Entry[]?newTable)?{??
  • ????????int?newCapacity?=?newTable.length;??
  • ????????for?(Entry<K,V>?e?=?header.after;?e?!=?header;?e?=?e.after)?{??
  • ????????????int?index?=?indexFor(e.hash,?newCapacity);??
  • ????????????e.next?=?newTable[index];??
  • ????????????newTable[index]?=?e;??
  • ????????}??
  • ????}??
  • ??
  • ??
  • ????//覆寫HashMap中的containsValue方法,??
  • ????//覆寫該方法的目的同樣是為了提高查詢的效率,??
  • ????//利用雙向循環鏈表的特點進行查詢,少了對數組的外層for循環??
  • ????public?boolean?containsValue(Object?value)?{??
  • ????????//?Overridden?to?take?advantage?of?faster?iterator??
  • ????????if?(value==null)?{??
  • ????????????for?(Entry?e?=?header.after;?e?!=?header;?e?=?e.after)??
  • ????????????????if?(e.value==null)??
  • ????????????????????return?true;??
  • ????????}?else?{??
  • ????????????for?(Entry?e?=?header.after;?e?!=?header;?e?=?e.after)??
  • ????????????????if?(value.equals(e.value))??
  • ????????????????????return?true;??
  • ????????}??
  • ????????return?false;??
  • ????}??
  • ??
  • ??
  • ????//覆寫HashMap中的get方法,通過getEntry方法獲取Entry對象。??
  • ????//注意這里的recordAccess方法,??
  • ????//如果鏈表中元素的排序規則是按照插入的先后順序排序的話,該方法什么也不做,??
  • ????//如果鏈表中元素的排序規則是按照訪問的先后順序排序的話,則將e移到鏈表的末尾處。??
  • ????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;??
  • ????}??
  • ??
  • ????//清空HashMap,并將雙向鏈表還原為只有頭結點的空鏈表??
  • ????public?void?clear()?{??
  • ????????super.clear();??
  • ????????header.before?=?header.after?=?header;??
  • ????}??
  • ??
  • ????//Enty的數據結構,多了兩個指向前后節點的引用??
  • ????private?static?class?Entry<K,V>?extends?HashMap.Entry<K,V>?{??
  • ????????//?These?fields?comprise?the?doubly?linked?list?used?for?iteration.??
  • ????????Entry<K,V>?before,?after;??
  • ??
  • ????????//調用父類的構造方法??
  • ????????Entry(int?hash,?K?key,?V?value,?HashMap.Entry<K,V>?next)?{??
  • ????????????super(hash,?key,?value,?next);??
  • ????????}??
  • ??
  • ????????//雙向循環鏈表中,刪除當前的Entry??
  • ????????private?void?remove()?{??
  • ????????????before.after?=?after;??
  • ????????????after.before?=?before;??
  • ????????}??
  • ??
  • ????????//雙向循環立鏈表中,將當前的Entry插入到existingEntry的前面??
  • ????????private?void?addBefore(Entry<K,V>?existingEntry)?{??
  • ????????????after??=?existingEntry;??
  • ????????????before?=?existingEntry.before;??
  • ????????????before.after?=?this;??
  • ????????????after.before?=?this;??
  • ????????}??
  • ??
  • ??
  • ????????//覆寫HashMap中的recordAccess方法(HashMap中該方法為空),??
  • ????????//當調用父類的put方法,在發現插入的key已經存在時,會調用該方法,??
  • ????????//調用LinkedHashmap覆寫的get方法時,也會調用到該方法,??
  • ????????//該方法提供了LRU算法的實現,它將最近使用的Entry放到雙向循環鏈表的尾部,??
  • ????????//accessOrder為true時,get方法會調用recordAccess方法??
  • ????????//put方法在覆蓋key-value對時也會調用recordAccess方法??
  • ????????//它們導致Entry最近使用,因此將其移到雙向鏈表的末尾??
  • ????????void?recordAccess(HashMap<K,V>?m)?{??
  • ????????????LinkedHashMap<K,V>?lm?=?(LinkedHashMap<K,V>)m;??
  • ????????????//如果鏈表中元素按照訪問順序排序,則將當前訪問的Entry移到雙向循環鏈表的尾部,??
  • ????????????//如果是按照插入的先后順序排序,則不做任何事情。??
  • ????????????if?(lm.accessOrder)?{??
  • ????????????????lm.modCount++;??
  • ????????????????//移除當前訪問的Entry??
  • ????????????????remove();??
  • ????????????????//將當前訪問的Entry插入到鏈表的尾部??
  • ????????????????addBefore(lm.header);??
  • ????????????}??
  • ????????}??
  • ??
  • ????????void?recordRemoval(HashMap<K,V>?m)?{??
  • ????????????remove();??
  • ????????}??
  • ????}??
  • ??
  • ????//迭代器??
  • ????private?abstract?class?LinkedHashIterator<T>?implements?Iterator<T>?{??
  • ????Entry<K,V>?nextEntry????=?header.after;??
  • ????Entry<K,V>?lastReturned?=?null;??
  • ??
  • ????/**?
  • ?????*?The?modCount?value?that?the?iterator?believes?that?the?backing?
  • ?????*?List?should?have.??If?this?expectation?is?violated,?the?iterator?
  • ?????*?has?detected?concurrent?modification.?
  • ?????*/??
  • ????int?expectedModCount?=?modCount;??
  • ??
  • ????public?boolean?hasNext()?{??
  • ????????????return?nextEntry?!=?header;??
  • ????}??
  • ??
  • ????public?void?remove()?{??
  • ????????if?(lastReturned?==?null)??
  • ????????throw?new?IllegalStateException();??
  • ????????if?(modCount?!=?expectedModCount)??
  • ????????throw?new?ConcurrentModificationException();??
  • ??
  • ????????????LinkedHashMap.this.remove(lastReturned.key);??
  • ????????????lastReturned?=?null;??
  • ????????????expectedModCount?=?modCount;??
  • ????}??
  • ??
  • ????//從head的下一個節點開始迭代??
  • ????Entry<K,V>?nextEntry()?{??
  • ????????if?(modCount?!=?expectedModCount)??
  • ????????throw?new?ConcurrentModificationException();??
  • ????????????if?(nextEntry?==?header)??
  • ????????????????throw?new?NoSuchElementException();??
  • ??
  • ????????????Entry<K,V>?e?=?lastReturned?=?nextEntry;??
  • ????????????nextEntry?=?e.after;??
  • ????????????return?e;??
  • ????}??
  • ????}??
  • ??
  • ????//key迭代器??
  • ????private?class?KeyIterator?extends?LinkedHashIterator<K>?{??
  • ????public?K?next()?{?return?nextEntry().getKey();?}??
  • ????}??
  • ??
  • ????//value迭代器??
  • ????private?class?ValueIterator?extends?LinkedHashIterator<V>?{??
  • ????public?V?next()?{?return?nextEntry().value;?}??
  • ????}??
  • ??
  • ????//Entry迭代器??
  • ????private?class?EntryIterator?extends?LinkedHashIterator<Map.Entry<K,V>>?{??
  • ????public?Map.Entry<K,V>?next()?{?return?nextEntry();?}??
  • ????}??
  • ??
  • ????//?These?Overrides?alter?the?behavior?of?superclass?view?iterator()?methods??
  • ????Iterator<K>?newKeyIterator()???{?return?new?KeyIterator();???}??
  • ????Iterator<V>?newValueIterator()?{?return?new?ValueIterator();?}??
  • ????Iterator<Map.Entry<K,V>>?newEntryIterator()?{?return?new?EntryIterator();?}??
  • ??
  • ??
  • ????//覆寫HashMap中的addEntry方法,LinkedHashmap并沒有覆寫HashMap中的put方法,??
  • ????//而是覆寫了put方法所調用的addEntry方法和recordAccess方法,??
  • ????//put方法在插入的key已存在的情況下,會調用recordAccess方法,??
  • ????//在插入的key不存在的情況下,要調用addEntry插入新的Entry??
  • ????void?addEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{??
  • ????????//創建新的Entry,并插入到LinkedHashMap中??
  • ????????createEntry(hash,?key,?value,?bucketIndex);??
  • ??
  • ????????//雙向鏈表的第一個有效節點(header后的那個節點)為近期最少使用的節點??
  • ????????Entry<K,V>?eldest?=?header.after;??
  • ????????//如果有必要,則刪除掉該近期最少使用的節點,??
  • ????????//這要看對removeEldestEntry的覆寫,由于默認為false,因此默認是不做任何處理的。??
  • ????????if?(removeEldestEntry(eldest))?{??
  • ????????????removeEntryForKey(eldest.key);??
  • ????????}?else?{??
  • ????????????//擴容到原來的2倍??
  • ????????????if?(size?>=?threshold)??
  • ????????????????resize(2?*?table.length);??
  • ????????}??
  • ????}??
  • ??
  • ????void?createEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{??
  • ????????//創建新的Entry,并將其插入到數組對應槽的單鏈表的頭結點處,這點與HashMap中相同??
  • ????????HashMap.Entry<K,V>?old?=?table[bucketIndex];??
  • ????????Entry<K,V>?e?=?new?Entry<K,V>(hash,?key,?value,?old);??
  • ????????table[bucketIndex]?=?e;??
  • ????????//每次插入Entry時,都將其移到雙向鏈表的尾部,??
  • ????????//這便會按照Entry插入LinkedHashMap的先后順序來迭代元素,??
  • ????????//同時,新put進來的Entry是最近訪問的Entry,把其放在鏈表末尾?,符合LRU算法的實現??
  • ????????e.addBefore(header);??
  • ????????size++;??
  • ????}??
  • ??
  • ????//該方法是用來被覆寫的,一般如果用LinkedHashmap實現LRU算法,就要覆寫該方法,??
  • ????//比如可以將該方法覆寫為如果設定的內存已滿,則返回true,這樣當再次向LinkedHashMap中put??
  • ????//Entry時,在調用的addEntry方法中便會將近期最少使用的節點刪除掉(header后的那個節點)。??
  • ????protected?boolean?removeEldestEntry(Map.Entry<K,V>?eldest)?{??
  • ????????return?false;??
  • ????}??
  • }??
  • ? ? 幾點總結

    ? ? 關于LinkedHashMap的源碼,給出以下幾點比較重要的總結:

    ? ? 1、從源碼中可以看出,LinkedHashMap中加入了一個head頭結點,將所有插入到該LinkedHashMap中的Entry按照插入的先后順序依次加入到以head為頭結點的雙向循環鏈表的尾部。


    ? ? 實際上就是HashMap和LinkedList兩個集合類的存儲結構的結合。在LinkedHashMapMap中,所有put進來的Entry都保存在如第一個圖所示的哈希表中,但它又額外定義了一個以head為頭結點的空的雙向循環鏈表,每次put進來Entry,除了將其保存到對哈希表中對應的位置上外,還要將其插入到雙向循環鏈表的尾部。

    ? ? 2、LinkedHashMap由于繼承自HashMap,因此它具有HashMap的所有特性,同樣允許key和value為null。

    ? ? 3、注意源碼中的accessOrder標志位,當它false時,表示雙向鏈表中的元素按照Entry插入LinkedHashMap到中的先后順序排序,即每次put到LinkedHashMap中的Entry都放在雙向鏈表的尾部,這樣遍歷雙向鏈表時,Entry的輸出順序便和插入的順序一致,這也是默認的雙向鏈表的存儲順序;當它為true時,表示雙向鏈表中的元素按照訪問的先后順序排列,可以看到,雖然Entry插入鏈表的順序依然是按照其put到LinkedHashMap中的順序,但put和get方法均有調用recordAccess方法(put方法在key相同,覆蓋原有的Entry的情況下調用recordAccess方法),該方法判斷accessOrder是否為true,如果是,則將當前訪問的Entry(put進來的Entry或get出來的Entry)移到雙向鏈表的尾部(key不相同時,put新Entry時,會調用addEntry,它會調用creatEntry,該方法同樣將新插入的元素放入到雙向鏈表的尾部,既符合插入的先后順序,又符合訪問的先后順序,因為這時該Entry也被訪問了),否則,什么也不做。

    ? ? 4、注意構造方法,前四個構造方法都將accessOrder設為false,說明默認是按照插入順序排序的,而第五個構造方法可以自定義傳入的accessOrder的值,因此可以指定雙向循環鏈表中元素的排序規則,一般要用LinkedHashMap實現LRU算法,就要用該構造方法,將accessOrder置為true。

    ? ? 5、LinkedHashMap并沒有覆寫HashMap中的put方法,而是覆寫了put方法中調用的addEntry方法和recordAccess方法,我們回過頭來再看下HashMap的put方法:

    [java] view plaincopy
  • //?將“key-value”添加到HashMap中??????
  • public?V?put(K?key,?V?value)?{??????
  • ????//?若“key為null”,則將該鍵值對添加到table[0]中。??????
  • ????if?(key?==?null)??????
  • ????????return?putForNullKey(value);??????
  • ????//?若“key不為null”,則計算該key的哈希值,然后將其添加到該哈希值對應的鏈表中。??????
  • ????int?hash?=?hash(key.hashCode());??????
  • ????int?i?=?indexFor(hash,?table.length);??????
  • ????for?(Entry<K,V>?e?=?table[i];?e?!=?null;?e?=?e.next)?{??????
  • ????????Object?k;??????
  • ????????//?若“該key”對應的鍵值對已經存在,則用新的value取代舊的value。然后退出!??????
  • ????????if?(e.hash?==?hash?&&?((k?=?e.key)?==?key?||?key.equals(k)))?{??????
  • ????????????V?oldValue?=?e.value;??????
  • ????????????e.value?=?value;??????
  • ????????????e.recordAccess(this);??????
  • ????????????return?oldValue;??????
  • ????????}??????
  • ????}??????
  • ??
  • ????//?若“該key”對應的鍵值對不存在,則將“key-value”添加到table中??????
  • ????modCount++;????
  • ????//將key-value添加到table[i]處????
  • ????addEntry(hash,?key,?value,?i);??????
  • ????return?null;??????
  • }??????
  • ? ? 當要put進來的Entry的key在哈希表中已經在存在時,會調用recordAccess方法,當該key不存在時,則會調用addEntry方法將新的Entry插入到對應槽的單鏈表的頭部。

    ? ? 我們先來看recordAccess方法:

    [java] view plaincopy
  • //覆寫HashMap中的recordAccess方法(HashMap中該方法為空),??
  • //當調用父類的put方法,在發現插入的key已經存在時,會調用該方法,??
  • //調用LinkedHashmap覆寫的get方法時,也會調用到該方法,??
  • //該方法提供了LRU算法的實現,它將最近使用的Entry放到雙向循環鏈表的尾部,??
  • //accessOrder為true時,get方法會調用recordAccess方法??
  • //put方法在覆蓋key-value對時也會調用recordAccess方法??
  • //它們導致Entry最近使用,因此將其移到雙向鏈表的末尾??
  • ??????void?recordAccess(HashMap<K,V>?m)?{??
  • ??????????LinkedHashMap<K,V>?lm?=?(LinkedHashMap<K,V>)m;??
  • ????//如果鏈表中元素按照訪問順序排序,則將當前訪問的Entry移到雙向循環鏈表的尾部,??
  • ????//如果是按照插入的先后順序排序,則不做任何事情。??
  • ??????????if?(lm.accessOrder)?{??
  • ??????????????lm.modCount++;??
  • ????????//移除當前訪問的Entry??
  • ??????????????remove();??
  • ????????//將當前訪問的Entry插入到鏈表的尾部??
  • ??????????????addBefore(lm.header);??
  • ??????????}??
  • ??????}??
  • ? ? 該方法會判斷accessOrder是否為true,如果為true,它會將當前訪問的Entry(在這里指put進來的Entry)移動到雙向循環鏈表的尾部,從而實現雙向鏈表中的元素按照訪問順序來排序(最近訪問的Entry放到鏈表的最后,這樣多次下來,前面就是最近沒有被訪問的元素,在實現、LRU算法時,當雙向鏈表中的節點數達到最大值時,將前面的元素刪去即可,因為前面的元素是最近最少使用的),否則什么也不做。
    ? ? 再來看addEntry方法:

    [java] view plaincopy
  • //覆寫HashMap中的addEntry方法,LinkedHashmap并沒有覆寫HashMap中的put方法,??
  • //而是覆寫了put方法所調用的addEntry方法和recordAccess方法,??
  • //put方法在插入的key已存在的情況下,會調用recordAccess方法,??
  • //在插入的key不存在的情況下,要調用addEntry插入新的Entry??
  • ???void?addEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{??
  • ????//創建新的Entry,并插入到LinkedHashMap中??
  • ???????createEntry(hash,?key,?value,?bucketIndex);??
  • ??
  • ???????//雙向鏈表的第一個有效節點(header后的那個節點)為近期最少使用的節點??
  • ???????Entry<K,V>?eldest?=?header.after;??
  • ????//如果有必要,則刪除掉該近期最少使用的節點,??
  • ????//這要看對removeEldestEntry的覆寫,由于默認為false,因此默認是不做任何處理的。??
  • ???????if?(removeEldestEntry(eldest))?{??
  • ???????????removeEntryForKey(eldest.key);??
  • ???????}?else?{??
  • ????????//擴容到原來的2倍??
  • ???????????if?(size?>=?threshold)??
  • ???????????????resize(2?*?table.length);??
  • ???????}??
  • ???}??
  • ??
  • ???void?createEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{??
  • ????//創建新的Entry,并將其插入到數組對應槽的單鏈表的頭結點處,這點與HashMap中相同??
  • ???????HashMap.Entry<K,V>?old?=?table[bucketIndex];??
  • ????Entry<K,V>?e?=?new?Entry<K,V>(hash,?key,?value,?old);??
  • ???????table[bucketIndex]?=?e;??
  • ????//每次插入Entry時,都將其移到雙向鏈表的尾部,??
  • ????//這便會按照Entry插入LinkedHashMap的先后順序來迭代元素,??
  • ????//同時,新put進來的Entry是最近訪問的Entry,把其放在鏈表末尾?,符合LRU算法的實現??
  • ???????e.addBefore(header);??
  • ???????size++;??
  • ???}??
  • ? ? 同樣是將新的Entry插入到table中對應槽所對應單鏈表的頭結點中,但可以看出,在createEntry中,同樣把新put進來的Entry插入到了雙向鏈表的尾部,從插入順序的層面來說,新的Entry插入到雙向鏈表的尾部,可以實現按照插入的先后順序來迭代Entry,而從訪問順序的層面來說,新put進來的Entry又是最近訪問的Entry,也應該將其放在雙向鏈表的尾部。

    ? ? 上面還有個removeEldestEntry方法,該方法如下:

    [java] view plaincopy
  • ????//該方法是用來被覆寫的,一般如果用LinkedHashmap實現LRU算法,就要覆寫該方法,??
  • ????//比如可以將該方法覆寫為如果設定的內存已滿,則返回true,這樣當再次向LinkedHashMap中put??
  • ????//Entry時,在調用的addEntry方法中便會將近期最少使用的節點刪除掉(header后的那個節點)。??
  • ????protected?boolean?removeEldestEntry(Map.Entry<K,V>?eldest)?{??
  • ????????return?false;??
  • ????}??
  • }??
  • ? ? 該方法默認返回false,我們一般在用LinkedHashMap實現LRU算法時,要覆寫該方法,一般的實現是,當設定的內存(這里指節點個數)達到最大值時,返回true,這樣put新的Entry(該Entry的key在哈希表中沒有已經存在)時,就會調用removeEntryForKey方法,將最近最少使用的節點刪除(head后面的那個節點,實際上是最近沒有使用)。
    ? ? 6、LinkedHashMap覆寫了HashMap的get方法:

    [java] view plaincopy
  • //覆寫HashMap中的get方法,通過getEntry方法獲取Entry對象。??
  • //注意這里的recordAccess方法,??
  • //如果鏈表中元素的排序規則是按照插入的先后順序排序的話,該方法什么也不做,??
  • //如果鏈表中元素的排序規則是按照訪問的先后順序排序的話,則將e移到鏈表的末尾處。??
  • ???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;??
  • ???}??
  • ? ? 先取得Entry,如果不為null,一樣調用recordAccess方法,上面已經說得很清楚,這里不在多解釋了。? ? 7、最后說說LinkedHashMap是如何實現LRU的。首先,當accessOrder為true時,才會開啟按訪問順序排序的模式,才能用來實現LRU算法。我們可以看到,無論是put方法還是get方法,都會導致目標Entry成為最近訪問的Entry,因此便把該Entry加入到了雙向鏈表的末尾(get方法通過調用recordAccess方法來實現,put方法在覆蓋已有key的情況下,也是通過調用recordAccess方法來實現,在插入新的Entry時,則是通過createEntry中的addBefore方法來實現),這樣便把最近使用了的Entry放入到了雙向鏈表的后面,多次操作后,雙向鏈表前面的Entry便是最近沒有使用的,這樣當節點個數滿的時候,刪除的最前面的Entry(head后面的那個Entry)便是最近最少使用的Entry。

    轉載于:https://www.cnblogs.com/xuyatao/p/6917145.html

    總結

    以上是生活随笔為你收集整理的转:【Java集合源码剖析】LinkedHashmap源码剖析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。