LinkedHashMap原始碼分析與LRU實現
LinkedHashMap可認為是雜湊表和連結列表綜合實現,並允許使用null值和null鍵。LinkedHashMap實現與HashMap的不同之處在於,LinkedHashMap維護著一個運行於所有條目的雙重連結列表。此連結列表定義了迭代順序,該迭代順序可以是插入順序或者是訪問順序。 LinkedHashMap的實現不是同步的。如果多個執行緒同時訪問LinkedHashMap,而其中至少一個執行緒從結構上修改了該對映,則它必須保持外部同步。
1.LinkedHashMap的儲存結構
LinkedHashMap中加入了一個head頭結點,將所有插入到該LinkedHashMap中的Entry按照插入的先後順序(accessOrder標誌位預設為false)依次加入到以head為頭結點的雙向迴圈連結串列的尾部。
LinkedHashMap實際上就是HashMap和LinkedList兩個集合類的儲存結構的結合。在LinkedHashMapMap中,所有put進來的Entry都儲存在如圖所示的雜湊表中,但它又額外定義了一個以head為頭結點的空的雙向迴圈連結串列,每次put進來Entry,除了將其儲存到對雜湊表中對應的位置上外,還要將其插入到雙向迴圈連結串列的尾部。
下面我們來分析LinkedHashMap的原始碼。
2.LinkedHashMap成員變數
LinkedHashMap採用的hash演算法和HashMap相同,但它重新定義了陣列中儲存的元素Entry,該Entry除了儲存當前物件的引用外,還儲存了其上一個元素before和下一個元素after的引用
- 1.//雙向迴圈連結串列的頭結點,整個LinkedHashMap中只有一個header,
- 2.//(此連結串列不同於HashMap裡面的那個next連結串列)
- 3.//它將雜湊表中所有的Entry貫穿起來,header中不儲存key-value對,只儲存前後節點的引用
- 4. privatetransient Entry<K,V> header;
- 5.
- 6.//雙向連結串列中元素排序規則的標誌位。
- 7.//accessOrder為false,表示按插入順序排序
-
8.//accessOrder為true,表示按訪問順序排序
- 9. privatefinalboolean accessOrder;
- 10.
- 11.
- 12. /**
- 13. * LinkedHashMap的Entry元素。
- 14. * 繼承HashMap的Entry元素,又儲存了其上一個元素before和下一個元素after的引用。
- 15. */
- 16.privatestaticclass Entry<K,V> extends HashMap.Entry<K,V> {
- 17. Entry<K,V> before, after;
- 18. …… //Entry類涉及到的方法,下面會繼續分析
- 19.}
3.建構函式
LinkedList一共提供了五個構造方法。
- 1.// 構造方法1,構造一個指定初始容量和載入因子的、按照插入順序的LinkedList
- 2.//載入因子取預設的0.75f
- 3.
- 4.public LinkedHashMap(int initialCapacity, float loadFactor) {
- 5. super(initialCapacity, loadFactor);
- 6. accessOrder = false;
- 7.}
- 8.
- 9.// 構造方法2,構造一個指定初始容量的LinkedHashMap,取得鍵值對的順序是插入順序
- 10.//載入因子取預設的0.75f
- 11.
- 12.public LinkedHashMap(int initialCapacity) {
- 13. super(initialCapacity);
- 14. accessOrder = false;
- 15.}
- 16.
- 17.// 構造方法3,用預設的初始化容量和載入因子建立一個LinkedHashMap,取得鍵值對的順序是插入順序
- 18.//載入因子取預設的0.75f
- 19.
- 20.public LinkedHashMap() {
- 21. super();
- 22. accessOrder = false;
- 23.}
- 24.
- 25.// 構造方法4,通過傳入的map建立一個LinkedHashMap,容量為預設容量(16)和
- 26.//(map.zise()/DEFAULT_LOAD_FACTORY)+1的較大者,載入因子為預設值0.75
- 27.
- 28.public LinkedHashMap(Map<? extends K, ? extends V> m) {
- 29. super(m);
- 30. accessOrder = false;
- 31.}
- 32.
- 33.// 構造方法5,根據指定容量、載入因子和指定連結串列中的元素排序的規則 建立一個LinkedHashMap
- 34.public LinkedHashMap(int initialCapacity,
- 35. float loadFactor,
- 36. boolean accessOrder) {
- 37. super(initialCapacity, loadFactor);
- 38. this.accessOrder = accessOrder;
- 39.}
我們已經知道LinkedHashMap的Entry元素繼承HashMap的Entry,提供了雙向連結串列的功能。在HashMap的構造器中,最後會呼叫init()方法,進行相關的初始化,這個方法在HashMap的實現中是空方法(感嘆模板模式的精妙!),只是提供給子類實現相關的初始化呼叫。LinkedHashMap重寫了init()方法,在呼叫父類的構造方法完成構造後,進一步實現了對其元素Entry的初始化操作。分析init()方法,的確是對header進行了初始化,並構造成一個雙向迴圈連結串列(和LinkedList的儲存結構是一樣的)。
- 1.void init() {
- 2. header = new Entry<K,V>(-1, null, null, null);
- 3. header.before = header.after = header;
- 4.}
4.元素儲存
LinkedHashMap重寫了父類HashMap的put方法呼叫的子方法void addEntry(int hash, K key, V value, int bucketIndex) 和void createEntry(int hash, K key, V value, int bucketIndex),提供了自己特有的雙向連結列表的實現。
- 1.//覆寫HashMap中的addEntry方法,LinkedHashmap並沒有覆寫HashMap中的put方法,
- 2. //而是覆寫了put方法所呼叫的addEntry方法和recordAccess方法,
- 3. //put方法在插入的key已存在的情況下,會呼叫recordAccess方法,
- 4. //在插入的key不存在的情況下,要呼叫addEntry插入新的Entry
- 5.void addEntry(int hash, K key, V value, int bucketIndex) {
- 6. //建立新的Entry,並插入到LinkedHashMap中
- 7. createEntry(hash, key, value, bucketIndex);
- 8.
- 9. //雙向連結串列的第一個有效節點(header後的那個節點)為近期最少使用的節點
- 10. Entry<K,V> eldest = header.after;
- 11. //如果有必要,則刪除掉該近期最少使用的節點,
- 12. //這要看對removeEldestEntry的覆寫,由於預設為false,因此預設是不做任何處理的。
-
相關推薦
LinkedHashMap原始碼分析與LRU實現
LinkedHashMap可認為是雜湊表和連結列表綜合實現,並允許使用null值和null鍵。LinkedHashMap實現與HashMap的不同之處在於,LinkedHashMap維護著一個運行於所有條目的雙重連結列表。此連結列表定義了迭代順序,該迭代順序可以是插入
LinkedHashMap原始碼分析及實現LRU演算法
PS: 要先了解HashMap的實現原理HashMap原始碼分析 一、簡單介紹 public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
redis原始碼分析與思考(十七)——有序集合型別的命令實現(t_zset.c)
有序集合是集合的延伸,它儲存著集合元素的不可重複性,但不同的是,它是有序的,它利用每一個元素的分數來作為有序集合的排序依據,現在列出有序集合的命令: 有序集合命令 命令 對應操作 時
redis原始碼分析與思考(十六)——集合型別的命令實現(t_set.c)
集合型別是用來儲存多個字串的,與列表型別不一樣,集合中不允許有重複的元素,也不能以索引的方式來通過下標獲取值,集合中的元素還是無序的。在普通的集合上增刪查改外,集合型別還實現了多個集合的取交集、並集、差集,集合的命令如下表所示: 集合命
redis原始碼分析與思考(十五)——雜湊型別的命令實現(t_hash.c)
雜湊型別又叫做字典,在redis中,雜湊型別本身是一個鍵值對,而雜湊型別裡面也存貯著鍵值對,其對應關係是,每個雜湊型別的值對應著一個鍵值對或多對鍵值對,如圖所示: 雜湊型別命令 命令 對應操
redis原始碼分析與思考(十四)——列表型別的命令實現(t_list.c)
列表型別是用來存貯多個字串物件的結構。一個列表可以存貯232-1個元素,可以對列表兩端進行插入(push)、彈出(pop),還可以獲取指定範圍內的元素列表、獲取指定索引的元素等等,它可以靈活的充當棧和佇列的角色。下面列出列表的命令: 列
redis原始碼分析與思考(十三)——字串型別的命令實現(t_string.c)
在對字串操作的命令中,主要有增加刪查該、批處理操作以及編碼的轉換命令,現在列出對字串物件操作的主要常用命令: 常用命令表 命令 對應操作 時間複雜度
redis原始碼分析與思考(十七)——有序集合型別的命令實現(t_set.c)
有序集合是集合的延伸,它儲存著集合元素的不可重複性,但不同的是,它是有序的,它利用每一個元素的分數來作為有序集合的排序依據,現在列出有序集合的命令: 有序集合命令 命令 對應操作 時間複
手撕MyBatis底層原始碼分析與實現
MyBatis Hiberante 簡介 什麼是 MyBatis ? MyBatis 是一款優秀的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單
Java BAT大型公司面試必考技能視訊教程之HashMap原始碼分析與實現
視訊通過以下四個方面介紹了HASHMAP的內容 一、 什麼是HashMap Hash雜湊將一個任意的長度通過某種演算法(Hash函式演算法)轉換成一個固定的值。 MAP:地圖 x,y 儲存 總結:通過HASH出來的值,然後通過值定位到這個MAP,然後value儲存到這個M
面試必考之HashMap原始碼分析與實現
以下是JDK1.8之前版本的原始碼簡介 一、什麼是HashMap? Hash:雜湊將一個任意的長度通過某種(hash函式演算法)演算法轉換成一個固定值。 Map:儲存的集合、類似於地圖X,Y座
B/S結構,服務器端的結構分析與部分實現
生成 因此 puts kit 服務器 請求 cati 集成 servers 1.1 簡述 瀏覽器在訪問一個IP地址的時候,一般會自動在地址前方加上HTTP:// 表示其基於http協議訪問。 一般而言,http跟tcp在本質上沒有區別。 tcp連接的過程,在JAVA語言中
FIFO與LRU實現(Java)
固定 blank per shu static 置換 ted clas als 一、概述 在學操作系統的時候,會接觸到頁面緩存調度算法。緩存不可能是無限大的,所以會涉及到一些置換策略,來保證緩存的命中率。常見的有:FIFO、LRU、LFU、OPT策略等。 1、緩存置換算法
PHP 控制反轉與依賴注入詳細分析與程式碼實現
PHP有很多的設計模式,比如單例模式,訂閱模式,策略模式,工廠模式,觀察者模式,這些設計模式其實無非都是為了讓程式簡化,容易維護,模組間解耦。現在我們來講講PHP的另外一種設計模式,控制反轉/依賴注入,這兩者其實是同一個概念,只是凶不同的角度去解釋的而已。 依賴注入:是從需要實現的業務邏輯上面去
【Android】原始碼分析 - LRUCache快取實現原理
一、Android中的快取策略 一般來說,快取策略主要包含快取的新增、獲取和刪除這三類操作。如何新增和獲取快取這個比較好理解,那麼為什麼還要刪除快取呢?這是因為不管是記憶體快取還是硬碟快取,它們的快取大小都是有限的。當快取滿了之後,再想其新增快取,這個時候就需要刪除一些舊的快取
gh0st原始碼分析與遠控的編寫(一)
再過幾天期末考試了,還有好多要複習。。蛋都快碎了。最近在看老狼的gh0st核心程式設計,想了很久要不要寫文章,最後還是覺得很有必要,原因過一會講。 先送上老狼的gh0st無加密(lxe格式)視訊下載地址:
gh0st原始碼分析與遠控的編寫(四)
真的很久很久了,距離上一次寫gh0st的文章(http://www.mmcyy.com),過去有大半年了。總算有一個時間,我放下手裡所有的活,能夠繼續把這份努力延續下去。 以後對於gh0st的文章,就是一個一個模組的分析。原本gh
gh0st原始碼分析與遠控的編寫(三)
好久不見。距離上次寫gh0st來有好久了,一是期末考試,忙不開,二是後來電腦壞了,幾天沒能上網。 昨天總算是把電腦修好了,雖說沒到一切重頭開始的地步,但是也重灌各種東西花了很久。閒下來的時間,我就來繼續分析gh0st的原始碼吧。
gh0st原始碼分析與遠控的編寫(二)
上次說了那麼多,基本上就是一個叫“大局觀”的東西,只有腦子裡有了一個軟體的設計、執行思路,才能把一個一個類寫出來,組合在一起。 Gh0st的作者是一個對程式碼有很好掌控的人,他對程式碼的組合,類之間的關係,面向物件的思想有很深入的理解。而對我們看原始碼的人
redis原始碼分析與思考(十九)——AOF持久化
為了解決持久化檔案很龐大以及會阻塞伺服器的 情況,redis提出一種新的持久化方案:AOF持久化。AOF持久化是redis儲存資料的另外一種方式,全稱Append Only File,與RDB持久化不同的是,AOF持久化是隻儲存從客戶端鍵入