摘要:習(xí)慣在微信看技術(shù)文章,想要獲取更多的資源的同學(xué),可以關(guān)注微信公眾號(hào)。為了大家方便,剛新建了一下群,大家也可以去交流交流。謝謝支持了希望能多介紹給其他有需要的朋友
前言
聲明,本文用得是jdk1.8
前面已經(jīng)講了Collection的總覽和剖析List集合以及散列表、Map集合、紅黑樹(shù)還有HashMap基礎(chǔ)了:
Collection總覽
List集合就這么簡(jiǎn)單【源碼剖析】
Map集合、散列表、紅黑樹(shù)介紹
HashMap就是這么簡(jiǎn)單【源碼剖析】
本篇主要講解LinkedHashMap~
看這篇文章之前最好是有點(diǎn)數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ):
Java實(shí)現(xiàn)單向鏈表
棧和隊(duì)列就是這么簡(jiǎn)單
二叉樹(shù)就這么簡(jiǎn)單
當(dāng)然了,如果講得有錯(cuò)的地方還請(qǐng)大家多多包涵并不吝在評(píng)論去指正~
一、LinkedHashMap剖析LinkedHashMap數(shù)據(jù)結(jié)構(gòu)圖:
ps:圖片來(lái)源網(wǎng)絡(luò),侵刪~
首先我們來(lái)看看類(lèi)繼承圖:
我簡(jiǎn)單翻譯了一下頂部的注釋(我英文水平渣,如果有錯(cuò)的地方請(qǐng)多多包涵~歡迎在評(píng)論區(qū)下指正)
從頂部翻譯我們就可以歸納總結(jié)出HashMap幾點(diǎn):
底層是散列表和雙向鏈表
允許為null,不同步
插入的順序是有序的(底層鏈表致使有序)
裝載因子和初始容量對(duì)LinkedHashMap影響是很大的~
同時(shí)也給我?guī)Я藥讉€(gè)疑問(wèn):
access-ordered和insertion-ordered具體的使用和意思
為什么說(shuō)初始容量對(duì)遍歷沒(méi)有影響?
希望可以在看源碼的過(guò)程中可以解決掉我這兩個(gè)疑問(wèn)~那接下來(lái)就開(kāi)始吧~
下面我列舉就這兩個(gè)比較重要的:
這就印證了我們的LinkedHashMap底層確確實(shí)實(shí)是散列表和雙向鏈表~
在構(gòu)建新節(jié)點(diǎn)時(shí),構(gòu)建的是LinkedHashMap.Entry 不再是Node.
1.3構(gòu)造方法可以發(fā)現(xiàn),LinkedHashMap有5個(gè)構(gòu)造方法:
下面我們來(lái)看看構(gòu)造方法的定義是怎么樣的:
從構(gòu)造方法上我們可以知道的是:LinkedHashMap默認(rèn)使用的是插入順序
1.4put方法原本我是想要找put方法,看看是怎么實(shí)現(xiàn)的,后來(lái)沒(méi)找著,就奇了個(gè)怪~
再頓了一下,原來(lái)LinkedHashMap和HashMap的put方法是一樣的!LinkedHashMap繼承著HashMap,LinkedHashMap沒(méi)有重寫(xiě)HashMap的put方法
所以,LinkedHashMap的put方法和HashMap是一樣的。
如果沒(méi)看過(guò)HashMap就是這么簡(jiǎn)單【源碼剖析】的同學(xué),可進(jìn)去看看~
當(dāng)然了,在創(chuàng)建節(jié)點(diǎn)的時(shí)候,調(diào)用的是LinkedHashMap重寫(xiě)的方法~
1.5get方法get方法也是多了:判斷是否為訪(fǎng)問(wèn)順序~~~
講到了這里,感覺(jué)我們可以簡(jiǎn)單測(cè)試一波了:
首先我們來(lái)看看已插入順序來(lái)進(jìn)行插入和遍歷:
public static void insertOrder() { // 默認(rèn)是插入順序 LinkedHashMapinsertOrder = new LinkedHashMap(); String value = "關(guān)注公眾號(hào)Java3y"; int i = 0; insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); //遍歷 Set set = insertOrder.keySet(); for (Integer s : set) { String mapValue = insertOrder.get(s); System.out.println(s + "---" + mapValue); } }
測(cè)試一波:
接著,我們來(lái)測(cè)試一下以訪(fǎng)問(wèn)順序來(lái)進(jìn)行插入和遍歷:
public static void accessOrder() { // 設(shè)置為訪(fǎng)問(wèn)順序的方式 LinkedHashMapaccessOrder = new LinkedHashMap(16, 0.75f, true); String value = "關(guān)注公眾號(hào)Java3y"; int i = 0; accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); // 遍歷 Set sets = accessOrder.keySet(); for (Integer key : sets) { String mapValue = accessOrder.get(key); System.out.println(key + "---" + mapValue); } }
代碼看似是沒(méi)有問(wèn)題,但是運(yùn)行會(huì)出錯(cuò)的!
前面在看源碼注釋的時(shí)候我們就發(fā)現(xiàn)了:在A(yíng)ccessOrder的情況下,使用get方法也是結(jié)構(gòu)性的修改!
為了簡(jiǎn)單看出他倆的區(qū)別,下面我就直接用key來(lái)進(jìn)行看了~
以下是訪(fǎng)問(wèn)順序的測(cè)試:
public static void accessOrder() { // 設(shè)置為訪(fǎng)問(wèn)順序的方式 LinkedHashMapaccessOrder = new LinkedHashMap(16, 0.75f, true); String value = "關(guān)注公眾號(hào)Java3y"; int i = 0; accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); // 訪(fǎng)問(wèn)一下key為3的元素再進(jìn)行遍歷 accessOrder.get(3); // 遍歷 Set sets = accessOrder.keySet(); for (Integer key : sets) { System.out.println(key ); } }
測(cè)試結(jié)果:
以下是插入順序的測(cè)試(代碼就不貼了,和上面幾乎一樣):
我們可以這樣理解:最常用的將其放在鏈表的最后,不常用的放在鏈表的最前~
這個(gè)知識(shí)點(diǎn)以我的理解而言,它這個(gè)訪(fǎng)問(wèn)順序在LinkedHashMap如果不重寫(xiě)用處并不大~它是用來(lái)給別的實(shí)現(xiàn)進(jìn)行擴(kuò)展的
因?yàn)樽畛1皇褂玫脑卦俦闅v的時(shí)候卻放在了最后邊,在LinkedHashMap中我也沒(méi)找到對(duì)應(yīng)的方法來(lái)進(jìn)行調(diào)用~
一個(gè)removeEldestEntry(Map.Entry
還有一個(gè)是afterNodeInsertion(boolean evict)方法,新增時(shí)判斷是否需要?jiǎng)h除最久未被使用的元素?。?/p>
去網(wǎng)上搜了幾篇資料,都是講LRUMap的實(shí)現(xiàn)的(也就是對(duì)LinkedHashMap進(jìn)行擴(kuò)展),有興趣的同學(xué)可參考下列鏈接:
https://blog.csdn.net/exceptional_derek/article/details/11713255
http://www.php.cn/java-article-362041.html
https://www.jianshu.com/p/1a66529e1a2e
https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ%3D%3D&chksm=ebd639d5dca1b0c3ba5a26bd46d265544f4fdd468df6465e54d93da230c3457d4947e79eaf0c&idx=1&mid=2247485177&sn=93cfa2c2e6f3e5092e5850bdb5ea4cc3
1.6remove方法對(duì)于remove方法,在LinkedHashMap中也沒(méi)有重寫(xiě),它調(diào)用的還是父類(lèi)的HashMap的remove()方法,在LinkedHashMap中重寫(xiě)的是:afterNodeRemoval(Node
當(dāng)然了,在remove的時(shí)候會(huì)涉及到上面重寫(xiě)的方法:
1.7遍歷的方法Set
看到了這里,我們就知道為啥注釋說(shuō):初始容量對(duì)遍歷沒(méi)有影響
因?yàn)樗闅v的是LinkedHashMap內(nèi)部維護(hù)的一個(gè)雙向鏈表,而不是散列表(當(dāng)然了,鏈表雙向鏈表的元素都來(lái)源于散列表)
二、總結(jié)LinkedHashMap比HashMap多了一個(gè)雙向鏈表的維護(hù),在數(shù)據(jù)結(jié)構(gòu)而言它要復(fù)雜一些,閱讀源碼起來(lái)比較輕松一些,因?yàn)榇蠖喽加蒆ashMap實(shí)現(xiàn)了..
閱讀源碼的時(shí)候我們會(huì)發(fā)現(xiàn)多態(tài)是無(wú)處不在的~子類(lèi)用父類(lèi)的方法,子類(lèi)重寫(xiě)了父類(lèi)的部分方法即可達(dá)到不一樣的效果!
比如:LinkedHashMap并沒(méi)有重寫(xiě)put方法,而put方法內(nèi)部的newNode()方法重寫(xiě)了。LinkedHashMap調(diào)用父類(lèi)的put方法,里面回調(diào)的是重寫(xiě)后的newNode(),從而達(dá)到目的!
LinkedHashMap可以設(shè)置兩種遍歷順序:
訪(fǎng)問(wèn)順序(access-ordered)
插入順序(insertion-ordered)
默認(rèn)是插入順序的
對(duì)于訪(fǎng)問(wèn)順序,它是LRU(最近最少使用)算法的實(shí)現(xiàn),要使用它要么重寫(xiě)LinkedListMap的幾個(gè)方法(removeEldestEntry(Map.Entry
LinkedHashMap遍歷的是內(nèi)部維護(hù)的雙向鏈表,所以說(shuō)初始容量對(duì)LinkedHashMap遍歷是不受影響的
參考資料:
《Core Java》
https://blog.csdn.net/zxt0601/article/details/77429150
https://blog.csdn.net/panweiwei1994/article/details/76555359
https://zhuanlan.zhihu.com/p/28216267
https://blog.csdn.net/fan2012huan/article/details/51097331
https://www.cnblogs.com/chinajava/p/5808416.html
明天要是無(wú)意外的話(huà),可能會(huì)寫(xiě)TreeMap,敬請(qǐng)期待哦~~~~
文章的目錄導(dǎo)航:https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y。為了大家方便,剛新建了一下qq群:742919422,大家也可以去交流交流。謝謝支持了!希望能多介紹給其他有需要的朋友
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69024.html
摘要:下面總結(jié)一下集合常用的三個(gè)子類(lèi)吧無(wú)序,允許為,底層是散列表紅黑樹(shù),非線(xiàn)程同步有序,不允許為,底層是紅黑樹(shù)非線(xiàn)程同步迭代有序,允許為,底層是雙向鏈表,非線(xiàn)程同步從結(jié)論而言我們就可以根據(jù)自己的實(shí)際情況來(lái)使用了。 前言 聲明,本文用的是jdk1.8 前面章節(jié)回顧: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹(shù)介紹 HashMap就是這么簡(jiǎn)單【源碼...
摘要:在這種情況下,是以其為根的樹(shù)的最后一個(gè)結(jié)點(diǎn)。來(lái)源二總結(jié)底層是紅黑樹(shù),能夠?qū)崿F(xiàn)該集合有序如果在構(gòu)造方法中傳遞了對(duì)象,那么就會(huì)以對(duì)象的方法進(jìn)行比較。 前言 聲明,本文用得是jdk1.8 前面章節(jié)回顧: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹(shù)介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHashMap就這么簡(jiǎn)單【源碼剖析】 本...
摘要:而在集合中,值僅僅是一個(gè)對(duì)象罷了該對(duì)象對(duì)本身而言是無(wú)用的。將這篇文章作為集合的總結(jié)篇,但覺(jué)得沒(méi)什么好寫(xiě)就回答一些面試題去了,找了一會(huì)面試題又覺(jué)得不夠系統(tǒng)。 前言 聲明,本文用的是jdk1.8 花了一個(gè)星期,把Java容器核心的知識(shí)過(guò)了一遍,感覺(jué)集合已經(jīng)無(wú)所畏懼了??!(哈哈哈....),現(xiàn)在來(lái)總結(jié)一下吧~~ 回顧目錄: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Ma...
摘要:下面我來(lái)簡(jiǎn)單總結(jié)一下的核心要點(diǎn)底層結(jié)構(gòu)是散列表數(shù)組鏈表紅黑樹(shù),這一點(diǎn)和是一樣的。是將所有的方法進(jìn)行同步,效率低下。而作為一個(gè)高并發(fā)的容器,它是通過(guò)部分鎖定算法來(lái)進(jìn)行實(shí)現(xiàn)線(xiàn)程安全的。 前言 聲明,本文用的是jdk1.8 前面章節(jié)回顧: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹(shù)介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHas...
摘要:系統(tǒng)級(jí)線(xiàn)程核心級(jí)線(xiàn)程由操作系統(tǒng)內(nèi)核進(jìn)行管理。值得注意的是多線(xiàn)程的存在,不是提高程序的執(zhí)行速度。實(shí)現(xiàn)多線(xiàn)程上面說(shuō)了一大堆基礎(chǔ),理解完的話(huà)。虛擬機(jī)的啟動(dòng)是單線(xiàn)程的還是多線(xiàn)程的是多線(xiàn)程的。 前言 之前花了一個(gè)星期回顧了Java集合: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 Map集合、散列表、紅黑樹(shù)介紹 HashMap就是這么簡(jiǎn)單【源碼剖析】 LinkedHashMa...
閱讀 3495·2023-04-25 18:14
閱讀 1602·2021-11-24 09:38
閱讀 3330·2021-09-22 14:59
閱讀 3125·2021-08-09 13:43
閱讀 2644·2019-08-30 15:54
閱讀 619·2019-08-30 13:06
閱讀 1626·2019-08-30 12:52
閱讀 2776·2019-08-30 11:13