集合三兄弟List,Set,Map還分不清?
作為Java基礎(chǔ)知識(shí)的核心部分,集合方面是面試時(shí)的重中之重,List、Set、map等相信大家都不會(huì)陌生,當(dāng)然面試官也不會(huì)從簡單的問題出發(fā),因?yàn)樗惨呀?jīng)問吐了,今天就聊一下集合在面試中的高級(jí)部分,別再傻傻分不清了!

一、List、Map、Set三個(gè)接口,存取元素時(shí),各有什么特點(diǎn)?
(1)Set集合的add有一個(gè)boolean類型的返回值,當(dāng)集合中沒有某個(gè)元素時(shí),則可以成功加入該 元素,返回結(jié)果為true;當(dāng)集合中存在與某個(gè)元素equals方法相等 的元素時(shí),則無法加入該元素, 取元素時(shí)只能用Iterator接口取得所有元素,在逐一遍歷各個(gè)元素;
(2)List表示有先后順序的集合,調(diào)用add()方法,指定當(dāng)前對(duì)象在集合中的存放位置;一個(gè)對(duì)象可 以被反復(fù)存進(jìn)集合中;每調(diào)用一次add()方法,該對(duì)象就會(huì)被插入集合中一次,其實(shí),并不是把對(duì) 象本身存進(jìn)了集合中,而是在集合中使用一個(gè)索引變量指向了該對(duì)象,當(dāng)一個(gè)對(duì)象被add多次時(shí), 即有多個(gè)索引指向了這個(gè)對(duì)象。List去元素時(shí)可以使用Iterator取出所有元素,在逐一遍歷,還可 以使用get(int index)獲取指定下表的元素;
(3)Map是雙列元素的集合,調(diào)用put(key,value),要存儲(chǔ)一對(duì)key/value,不能存儲(chǔ)重復(fù)的key, 這個(gè)是根據(jù)eauals來判斷;取元素時(shí)用get(key)來獲取key所對(duì) 應(yīng)的value,另外還可以獲取 全部key,全部value
二、ArrayList 遍歷方式
第 1 種,普通 for 循環(huán)隨機(jī)訪問,通過索引值去遍歷。

第 2 種,通過迭代器遍歷。即通過 Iterator 去遍歷。

第 3 種,增強(qiáng) for 循環(huán)遍歷。

第 4 種 forEach + lambda 循環(huán)遍歷

四種遍歷比較
結(jié)論:如果數(shù)據(jù)量比較少的話貌似四種循環(huán)耗時(shí)都差不多,但是隨著數(shù)據(jù)量的增長會(huì)發(fā)現(xiàn) foreach 的效率是最好的。但是從上面我們會(huì)發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象,第一次循環(huán)的時(shí)候forEach遍歷的時(shí)間是最長的盡管數(shù)據(jù)量非常少也會(huì)這樣。但是后面的耗時(shí)就正常了。如果放開測(cè)試?yán)锩娴念A(yù)熱代碼,每次跑出來的耗時(shí)也是正常的。
三、ArrayList和LinkedList的底層實(shí)現(xiàn)原理?他們?yōu)槭裁淳€程不安全?在多線程并發(fā)操作下,我們應(yīng)該用什么替代?
1、ArrayList底層通過數(shù)組實(shí)現(xiàn),ArrayList允許按序號(hào)索引元素,而插入元素需要對(duì)數(shù)組進(jìn)行移位等內(nèi)存操作,所以索引快插入較慢;(擴(kuò)容方式)一旦我們實(shí)例化了ArrayList 無參構(gòu)造函數(shù)默認(rèn)數(shù)組長度為10。add方法底層如 果增加的元素超過了10個(gè),那么ArrayList底層會(huì)生成一個(gè)新的數(shù)組,長度為原來數(shù)組長度的1.5倍+1,然后將原數(shù)組內(nèi)容復(fù)制到新數(shù)組中,并且后續(xù)加的內(nèi)容都會(huì)放到新數(shù)組中。當(dāng)新數(shù)組無法容納增加元素時(shí),重復(fù)該過程;
2、LinkedList底層通過雙向鏈表實(shí)現(xiàn),取元素時(shí)需要進(jìn)行前項(xiàng)或后項(xiàng)的遍歷,插入元素時(shí)只需要記錄本項(xiàng)的前后 項(xiàng)即可,所以插入快查詢慢;
3、ArrayList和LinkedList底層方法都沒有加synchronized關(guān)鍵詞,多線程訪問時(shí)會(huì)出現(xiàn)多個(gè)線程先后更改數(shù)據(jù)造成得到的數(shù)據(jù)是臟數(shù)據(jù);多線程并發(fā)操作下使用Vector來代替,Vector底層也是數(shù)組,但底層方法都加synchronized關(guān)鍵字使線程安全,效率較ArrayList差;
四、HashMap和HashTable有什么區(qū)別?其底層實(shí)現(xiàn)是什么?CurrentHashMap的鎖機(jī)制又是如何?如果想將一個(gè)Map變?yōu)橛行虻?該如何實(shí)現(xiàn)?
1、區(qū)別:
(1)HashMap沒有實(shí)現(xiàn)synchronized線程非安全,HashTable實(shí)現(xiàn)了synchronized線程安全;
(2)HashMap允許key和value為null,而HashTable不允許
2、底層原理:數(shù)組+鏈表實(shí)現(xiàn)
3、ConcurrentHashMap鎖分段技術(shù):HashTable效率低下的原因,是因?yàn)樗L問HashTable的線程都必須競爭同一把鎖,那假如容器中有多把鎖,每一把鎖用于鎖住容器中的一部分?jǐn)?shù)據(jù),那么當(dāng)多線程訪問容器中不同的數(shù)據(jù)時(shí),線程間就不會(huì)存在鎖競爭,從而提高并發(fā)訪問率;ConcurrentHashMap使用的就是鎖分段技術(shù),首先將數(shù)據(jù)分成一段一段的存儲(chǔ),然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問其中一個(gè)數(shù)據(jù)時(shí),其他段的數(shù)據(jù)也能被其他線程訪問;
4、實(shí)現(xiàn)TreeMap
五、ArryList 注意點(diǎn)
謹(jǐn)慎使用 ArrayList 中的 subList 方法
ArrayList 的 subList 結(jié)果不可強(qiáng)轉(zhuǎn)成 ArrayList,否則會(huì)拋出 ClassCastException 異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList. 說明:subList 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList ,而是 ArrayList 的一個(gè)視圖,對(duì)于 SubList 子列表的所有操作最終會(huì)反映到原列表上。

運(yùn)行結(jié)果: Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList at com.workit.demo.listener.ArrayListTest.main(ArrayListTest.java:29)
在 subList 場(chǎng)景中,高度注意對(duì)原集合元素個(gè)數(shù)的修改,會(huì)導(dǎo)致子列表的遍歷、增加、 刪除均會(huì)產(chǎn) ConcurrentModificationException 異常。

初始化 List 的時(shí)候盡量指定它的容量大小。(盡量減少擴(kuò)容次數(shù))
最后:點(diǎn)個(gè)小贊,好運(yùn)不斷,來個(gè)關(guān)注,青春常駐

