瘋狂Java筆記之常見java集合的實(shí)現(xiàn)細(xì)節(jié)

Set和Map

1.Set和Map的關(guān)系

首先Set是一種集合元素?zé)o序纽帖,不可重復(fù)的集合。而Map則代表一種有多個(gè)key-value對(duì)組成的集合誉己,Map集合類似于傳統(tǒng)的關(guān)聯(lián)數(shù)據(jù)衣盾∈霸停看起來他們沒喲什么關(guān)聯(lián)劲绪,實(shí)際上Set和Map是有莫大的關(guān)聯(lián)的∨璩啵可以說Map是Set集合的擴(kuò)展贾富。

當(dāng)我們只看Map的Key時(shí),會(huì)發(fā)現(xiàn)所有的key不能重復(fù)牺六,key之間沒有順序颤枪。也就是說將Map所有的key集合起來就組成了一個(gè)set集合。Map也提供了如下方法來返回組成的set集合

Set<K> keySet()

對(duì)于一個(gè)Map集合而言淑际,它本質(zhì)上是一個(gè)關(guān)聯(lián)數(shù)組畏纲,關(guān)聯(lián)數(shù)組中的key-value對(duì)之間有嚴(yán)格的對(duì)應(yīng)關(guān)系扇住,那將key-value對(duì)捆綁在一起對(duì)待,如下所示:

java4.PNG

2.HashMap和HashSet

在HashSet里盗胀,系統(tǒng)采用Hash算法決定集合元素的存儲(chǔ)位置艘蹋,這樣可以保證快速存,取集合元素票灰;對(duì)于HashMap而言女阀,系統(tǒng)將value當(dāng)初key的‘附屬物’,系統(tǒng)根據(jù)Hash算法開決定key的存儲(chǔ)位置屑迂,這個(gè)可以保證快速存浸策,取集合key,而value總是緊隨key存儲(chǔ)。

集合號(hào)稱存儲(chǔ)的是Java對(duì)象惹盼,但實(shí)際上并不會(huì)真正將Java對(duì)象放入Set集合中庸汗,而只是在Set集合中保留這些對(duì)象的引用而己。也就是說手报,Java集合實(shí)際上是多個(gè)引用變量所組成的集合蚯舱,這些引用變量指向?qū)嶋H的Java對(duì)象。對(duì)于java集合他只是多個(gè)引用變量的集合昧诱。

當(dāng)程序試圖將一個(gè)key-value對(duì)放入HashMap中時(shí)晓淀,首先根據(jù)該key的hashCade()返回值決定該Entry的存儲(chǔ)位置—如果兩個(gè)Entry的key的hashCade返回值相同,那么它們的存儲(chǔ)位置相同:如果這兩個(gè)Entry的key通過equals比較返回true盏档,則新添加Entry的value將覆蓋集合中原有Entry的value凶掰,但key不會(huì)覆蓋;如果這兩個(gè)Entry的key通過equal比較返回false ,則新添加的Entry將與集合中原有的Entry形成Entry鏈,而且新添加的Entry位于Entry鏈的頭部

當(dāng)系統(tǒng)開始初始化HashMap時(shí)蜈亩,系統(tǒng)會(huì)創(chuàng)建一個(gè)長(zhǎng)度為capacity的Entry數(shù)組懦窘。這個(gè)數(shù)組可以存儲(chǔ)元素的位置被稱為“桶(bucket)”,每個(gè)bucket都有其指定的索引,系統(tǒng)可以根據(jù)其索引快速訪問該bucket里存儲(chǔ)的元素稚配。

無論何時(shí)畅涂,HashMap的每一個(gè)“桶”只存儲(chǔ)一個(gè)元素(即一個(gè)Entry).由于Entry對(duì)象可以包含一個(gè)引用變量(就是Entry構(gòu)造器的最后一個(gè)參數(shù))用于指向下一個(gè)Entry,因此可能出現(xiàn):HashMap的bucket中只有一個(gè)Entry,但這個(gè)Entry指向另一個(gè)Entry這就形成一個(gè)Entry鏈道川,如圖:


set.PNG

HashMap在每一個(gè)bucket里只有一個(gè)Entry,所以可以根據(jù)索引快速取出該bucket里的Enrty.當(dāng)發(fā)生hash沖突時(shí)午衰,單個(gè)bucket里存儲(chǔ)的不是一個(gè)Entry,而是一個(gè)Entry鏈,系統(tǒng)會(huì)按順序遍歷每個(gè)Entry,知道找到想搜到的Entry為止冒萄,即使要搜索的末端臊岸,系統(tǒng)也會(huì)循環(huán)到最后找到該元素。

3.TreeMap和TreeSet

TreeSet底層實(shí)際使用的容器就是TrenMap.絕大部分的方法都是直接調(diào)用TreeMap的方法來實(shí)現(xiàn)的尊流。而對(duì)于TreeMap而言帅戒,它采用一種被稱為‘紅黑樹’的排序二叉樹來保存Map中的每個(gè)Entry即每個(gè)Entry都是紅黑樹的一個(gè)節(jié)點(diǎn)。

對(duì)于TreeMap向言崖技,由于它底層采用一棵紅黑樹來保存集合中的Entry逻住,這意味著TreeMap添加元素钟哥、取出元素的性能都比HashMap低。當(dāng)TreeMag添加元素時(shí)瞎访,需要通過循壞找到新
增Entry的插入位置腻贰,因此比較耗性能;當(dāng)從TreeMap中取出元素時(shí),需要通過循環(huán)才能找到合適的Entry装诡,也比較耗性能·但TreeMap, TreeSet相比HashMag,HashSet的優(yōu)勢(shì)在于:'TreeMap中的所有Entry總是按key根據(jù)指定的排序規(guī)則保持有序狀態(tài)银受,TreeSet中的所有元素總是根據(jù)指定的排序規(guī)則保持有序狀態(tài)。

Map和List

1.Map的values()方法

不管是HashIvlap鸦采,還是TreeMap宾巍,它們的values()方法都可返回其所有value組成的Collection集合。按照通常理解渔伯,這個(gè)Collection集合應(yīng)該是一個(gè)List集合顶霞,因?yàn)镸ap的多個(gè)valu。允許重復(fù)锣吼。
但實(shí)際上选浑,HashMap,TreeMap的values()方法的實(shí)現(xiàn)要更巧妙。這兩個(gè)Mad對(duì)象的values()方法返回的是一個(gè)不存儲(chǔ)元素的Collection集合玄叠,當(dāng)程序遍歷Collection集合時(shí)古徒,實(shí)際上就是遍歷Map對(duì)象的value

HashMap和TreeMap的values()方法并未把Map中的value重新組合成一個(gè)包含元素的集合對(duì)象,這樣就可以降低系統(tǒng)內(nèi)存開銷读恃。

2.Map和List的關(guān)系

  • 從底層實(shí)現(xiàn)來看隧膘,Set和Map很相似;從用法的角度來看寺惫,Map和List也有很大的相似之處疹吃。

1.Map接口提供了get(K key)方法,允許Map對(duì)象根據(jù)key來取得value.
2.List接口提供了get(int index)方法西雀,允許list對(duì)象根據(jù)元素索引來取得value

Map和List在底層實(shí)現(xiàn)上沒有太大的相似之處萨驶,只是用法有一些相似之處。

ArrayList和LinkedList

1.Vector和ArrayList的區(qū)別

Vector和ArrayList這個(gè)兩個(gè)集合類的本質(zhì)并沒有太大的不同艇肴,它們都實(shí)現(xiàn)了List接口腔呜,而且底層都是基于Java數(shù)組來存儲(chǔ)集合元素的。

此外從序列化機(jī)制的角度看再悼,ArrayList的實(shí)現(xiàn)比Vector的實(shí)現(xiàn)更安全
另外Vector是ArrayList的線程安全版本核畴,ArrayList和Vector覺大部分方法的實(shí)現(xiàn)都是相同的,只是Vector的方法增加了synchronized修飾帮哈。

2.ArrayList和LinkedList的實(shí)現(xiàn)差異

List代表一種線性表的數(shù)據(jù)結(jié)構(gòu)。ArrayList則是一種順序存儲(chǔ)的線性表锰镀,ArrayList底層采用數(shù)組來保存每個(gè)集合元素娘侍,LinkedList則是一種鏈?zhǔn)酱鎯?chǔ)的線性表咖刃,其本質(zhì)上就是一個(gè)雙向鏈表,但它不僅實(shí)現(xiàn)了List接口憾筏,還實(shí)現(xiàn)了Deque接口嚎杨。也就是說,LinkedList既可以當(dāng)成雙向鏈表使用氧腰,也可以當(dāng)成隊(duì)列使用枫浙,還可以當(dāng)成棧來使用(Deque代表雙端隊(duì)列,既具有隊(duì)列的特征.也具有棧的特征)古拴。

ArrayList
因?yàn)锳rrayList底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組箩帚,所以我們插入元素是需要完成兩件事:

  • 保證ArrayList底層封裝的數(shù)組長(zhǎng)度大于集合數(shù)據(jù)長(zhǎng)度
  • 插入之前將所有元素“整體搬家”,向后移動(dòng)一格

同理在刪除元素是也要對(duì)元素進(jìn)行“整體搬家”黄痪,這就導(dǎo)致增加和刪除的性能非常差紧帕,當(dāng)時(shí)在取出數(shù)據(jù)元素時(shí),性能基本和數(shù)組是一樣的桅打。

LinkedList
因?yàn)長(zhǎng)inkedSet是采用雙向鏈表的是嗜,如果單純的添加某個(gè)節(jié)點(diǎn)性能是很好的,當(dāng)時(shí)如果需要指定索引處添加節(jié)點(diǎn)挺尾,LinkedList必須必須先找到索引處的節(jié)點(diǎn)鹅搪,這個(gè)搜索過程系統(tǒng)開銷也是不少的,刪除也同理遭铺,如下圖所示:


LinkedList.PNG
LinkedList2.PNG

不過弊端是對(duì)于ArrayList而言丽柿,由于它底層采用數(shù)組來保存集合元素,因此可以直接根據(jù)數(shù)組索引取出index位置的元素;但對(duì)于LinkedList就比較麻煩掂僵,LinkedList必須逐個(gè)元素地搜索航厚,直到找到第index個(gè)元素為止。所以性能相對(duì)較低锰蓬。

3.ArrayList和LinkedList的性能分析和適用場(chǎng)景

當(dāng)程序需要以get(int index)獲取List集合指定的索引出的元素幔睬,ArrayList性能大大的優(yōu)于LinkedList。因?yàn)锳rrayList底層以數(shù)組來保存集合元素芹扭,所以調(diào)用get(int index)方法獲取指定索引處的元素時(shí)麻顶,底層實(shí)際調(diào)用elementData[index]來返回改元素,因此性能非常好舱卡,而LinkedList則必須逐個(gè)的搜索辅肾。

當(dāng)程序調(diào)用add(int index,Object obj)向List添加數(shù)據(jù)是,ArrayList需要“整體搬家”才能實(shí)現(xiàn)添加轮锥,而LinkedList需要找到索引而不用整體搬家矫钓,當(dāng)時(shí)找索引也需要消耗一些系統(tǒng)性能,因?yàn)樗侵饌€(gè)搜索。同理新娜,刪除也是這樣子赵辕。

當(dāng)添加的數(shù)據(jù)個(gè)數(shù)大于底層數(shù)組的長(zhǎng)度時(shí),那么ArrayList必須創(chuàng)建一個(gè)長(zhǎng)度為原來長(zhǎng)度1.5倍的數(shù)組概龄,再由垃圾回收機(jī)制進(jìn)行回收还惠。這樣系統(tǒng)開銷也有點(diǎn)大了。而LinkedList就不存在這個(gè)問題私杜。

不過從大多數(shù)應(yīng)用場(chǎng)景來說ArrayList總體性能還是優(yōu)于LinkedList蚕键。

Iterator迭代器

1.Iterator實(shí)現(xiàn)類與迭代器模式

Java的lteratar和Enumeration兩個(gè)接口都是迭代器模式的代表之作,它們就是迭代器模式里的“迭代器接口”衰粹。所謂迭代器模式指的是锣光,系統(tǒng)為遍歷多種數(shù)據(jù)列表、集合寄猩,容器提供一個(gè)標(biāo)準(zhǔn)的“迭代器接口”嫉晶,這些數(shù)據(jù)列表、集合田篇、容器就可面向相同的“迭代器接口”編程替废,通過相同的迭代器接口訪問不同數(shù)據(jù)列表‘集合、容器里的數(shù)據(jù).不同的數(shù)據(jù)列表泊柬、集合椎镣、容器如何實(shí)現(xiàn)這個(gè)“迭代器接口”,
則交給各數(shù)據(jù)列表兽赁、集合状答、容器自己完成。

2.迭代是刪除指定元素

對(duì)于TreeSet, HashSet等Set集合而言刀崖,當(dāng)使用Iterator遍歷它們時(shí)惊科,如果正在遍歷最后一個(gè)集合元素,那么使用Set集合的remove()方法刪除集合的任意元素并不會(huì)引發(fā)ConcurrentModificatianException異常亮钦,當(dāng)正在遍歷其他元素時(shí)刪除集合的任意元素都將引發(fā)該異常馆截。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蜂莉,隨后出現(xiàn)的幾起案子蜡娶,更是在濱河造成了極大的恐慌,老刑警劉巖映穗,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窖张,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蚁滋,警方通過查閱死者的電腦和手機(jī)宿接,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門赘淮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人睦霎,你說我怎么就攤上這事拥知。” “怎么了碎赢?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)速梗。 經(jīng)常有香客問我肮塞,道長(zhǎng),這世上最難降的妖魔是什么姻锁? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任枕赵,我火速辦了婚禮,結(jié)果婚禮上位隶,老公的妹妹穿的比我還像新娘拷窜。我一直安慰自己,他們只是感情好涧黄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布篮昧。 她就那樣靜靜地躺著,像睡著了一般笋妥。 火紅的嫁衣襯著肌膚如雪懊昨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天春宣,我揣著相機(jī)與錄音酵颁,去河邊找鬼。 笑死月帝,一個(gè)胖子當(dāng)著我的面吹牛躏惋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嚷辅,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼簿姨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了潦蝇?” 一聲冷哼從身側(cè)響起款熬,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎攘乒,沒想到半個(gè)月后贤牛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡则酝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年殉簸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闰集。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡般卑,死狀恐怖武鲁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝠检,我是刑警寧澤沐鼠,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站叹谁,受9級(jí)特大地震影響饲梭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜焰檩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一憔涉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧析苫,春花似錦兜叨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茫死,卻和暖如春议街,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背璧榄。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工特漩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骨杂。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓涂身,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親搓蚪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蛤售,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容