前言
聲明,本文用的是jdk1.8
花了一個(gè)星期析砸,把Java容器核心的知識(shí)過了一遍昔字,感覺集合已經(jīng)無所畏懼了!!(哈哈哈....)作郭,現(xiàn)在來總結(jié)一下吧~~
回顧目錄:
- Collection總覽
- List集合就這么簡(jiǎn)單【源碼剖析】
- Map集合陨囊、散列表、紅黑樹介紹
- HashMap就是這么簡(jiǎn)單【源碼剖析】
- LinkedHashMap就這么簡(jiǎn)單【源碼剖析】
- TreeMap就這么簡(jiǎn)單【源碼剖析】
- ConcurrentHashMap基于JDK1.8源碼剖析
- Set集合就這么簡(jiǎn)單夹攒!
Java容器可分為兩大類:
- Collection
- List
- ArrayList
- LinkedList
- Vector(了解蜘醋,已過時(shí))
- Set
-
HashSet
- LinkedHashSet
- TreeSet
-
HashSet
- List
- Map
-
HashMap
- LinkedHashMap
- TreeMap
- ConcurrentHashMap
- Hashtable(了解,咏尝,已過時(shí))
-
HashMap
著重標(biāo)出的那些就是我們用得最多的容器压语。
其實(shí),我也不知道要怎么總結(jié)好编检,因?yàn)橹皩懨恳黄臅r(shí)候都總結(jié)過了√ナ常現(xiàn)在又把他們重新羅列出來好像有點(diǎn)水,所以允懂,我決定去回答一些Java容器的面試題厕怜!
當(dāng)然了,我的答案未必就是正確的蕾总。如果有錯(cuò)誤的地方大家多多包含粥航,希望不吝在評(píng)論區(qū)留言指正~~
一、ArrayList和Vector的區(qū)別
共同點(diǎn):
- 這兩個(gè)類都實(shí)現(xiàn)了List接口生百,它們都是有序的集合(存儲(chǔ)有序)递雀,底層是數(shù)組。我們可以按位置索引號(hào)取出某個(gè)元素蚀浆,允許元素重復(fù)和為null缀程。
區(qū)別:
-
同步性:
- ArrayList是非同步的
- Vector是同步的
- 即便需要同步的時(shí)候,我們可以使用Collections工具類來構(gòu)建出同步的ArrayList而不用Vector
-
擴(kuò)容大欣弧:
- Vector增長(zhǎng)原來的一倍杠输,ArrayList增長(zhǎng)原來的0.5倍
二、HashMap和Hashtable的區(qū)別
共同點(diǎn):
- 從存儲(chǔ)結(jié)構(gòu)和實(shí)現(xiàn)來講基本上都是相同的秕衙,都是實(shí)現(xiàn)Map接口~
區(qū)別:
-
同步性:
- HashMap是非同步的
- Hashtable是同步的
- 需要同步的時(shí)候蠢甲,我們往往不使用,而使用ConcurrentHashMapConcurrentHashMap基于JDK1.8源碼剖析
-
是否允許為null:
- HashMap允許為null
- Hashtable不允許為null
-
contains方法
- 這知識(shí)點(diǎn)是在啪萃客網(wǎng)刷到的鹦牛,沒想到這種題還會(huì)有(我不太喜歡)....
- Hashtable有contains方法
- HashMap把Hashtable的contains方法去掉了,改成了containsValue和containsKey
-
繼承不同:
- HashMap
- public class Hashtable
三勇吊、List和Map的區(qū)別
共同點(diǎn):
- 都是Java常用的容器曼追,都是接口(ps:寫出來感覺好像和沒寫一樣.....)
不同點(diǎn):
-
存儲(chǔ)結(jié)構(gòu)不同:
- List是存儲(chǔ)單列的集合
- Map存儲(chǔ)的是key-value鍵值對(duì)的集合
-
元素是否可重復(fù):
- List允許元素重復(fù)
- Map不允許key重復(fù)
-
是否有序:
- List集合是有序的(存儲(chǔ)有序)
- Map集合是無序的(存儲(chǔ)無序)
四、Set里的元素是不能重復(fù)的汉规,那么用什么方法來區(qū)分重復(fù)與否呢? 是用==還是equals()?
我們知道Set集合實(shí)際大都使用的是Map集合的put方法來添加元素礼殊。
以HashSet為例驹吮,HashSet里的元素不能重復(fù),在源碼(HashMap)是這樣體現(xiàn)的:
// 1\. 如果key 相等
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 2\. 修改對(duì)應(yīng)的value
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
添加元素的時(shí)候晶伦,如果key(也對(duì)應(yīng)的Set集合的元素)相等碟狞,那么則修改value值。而在Set集合中婚陪,value值僅僅是一個(gè)Object對(duì)象罷了(該對(duì)象對(duì)Set本身而言是無用的)族沃。
也就是說:Set集合如果添加的元素相同時(shí),是根本沒有插入的(僅修改了一個(gè)無用的value值)泌参!從源碼(HashMap)中也看出來脆淹,==和equals()方法都有使用!
五沽一、Collection和Collections的區(qū)別
- Collection是集合的上級(jí)接口盖溺,繼承它的有Set和List接口
- Collections是集合的工具類,提供了一系列的靜態(tài)方法對(duì)集合的搜索锯玛、查找咐柜、同步等操作
六兼蜈、說出ArrayList,LinkedList的存儲(chǔ)性能和特性
ArrayList的底層是數(shù)組攘残,LinkedList的底層是雙向鏈表。
- ArrayList它支持以角標(biāo)位置進(jìn)行索引出對(duì)應(yīng)的元素(隨機(jī)訪問)为狸,而LinkedList則需要遍歷整個(gè)鏈表來獲取對(duì)應(yīng)的元素歼郭。因此一般來說ArrayList的訪問速度是要比LinkedList要快的
- ArrayList由于是數(shù)組,對(duì)于刪除和修改而言消耗是比較大(復(fù)制和移動(dòng)數(shù)組實(shí)現(xiàn))辐棒,LinkedList是雙向鏈表刪除和修改只需要修改對(duì)應(yīng)的指針即可病曾,消耗是很小的。因此一般來說LinkedList的增刪速度是要比ArrayList要快的
6.1擴(kuò)展:
ArrayList的增刪未必就是比LinkedList要慢漾根。
- 如果增刪都是在末尾來操作【每次調(diào)用的都是remove()和add()】泰涂,此時(shí)ArrayList就不需要移動(dòng)和復(fù)制數(shù)組來進(jìn)行操作了。如果數(shù)據(jù)量有百萬級(jí)的時(shí)辐怕,速度是會(huì)比LinkedList要快的逼蒙。(我測(cè)試過)
- 如果刪除操作的位置是在中間。由于LinkedList的消耗主要是在遍歷上寄疏,ArrayList的消耗主要是在移動(dòng)和復(fù)制上(底層調(diào)用的是arraycopy()方法是牢,是native方法)。
- LinkedList的遍歷速度是要慢于ArrayList的復(fù)制移動(dòng)速度的
- 如果數(shù)據(jù)量有百萬級(jí)的時(shí)陕截,還是ArrayList要快驳棱。(我測(cè)試過)
七、Enumeration和Iterator接口的區(qū)別
這個(gè)我在前面的文章中也沒有詳細(xì)去講它們农曲,只是大概知道的是:Iterator替代了Enumeration社搅,Enumeration是一個(gè)舊的迭代器了。
與Enumeration相比,Iterator更加安全形葬,因?yàn)楫?dāng)一個(gè)集合正在被遍歷的時(shí)候却汉,它會(huì)阻止其它線程去修改集合。
- 我們?cè)谧鼍毩?xí)的時(shí)候荷并,迭代時(shí)會(huì)不會(huì)經(jīng)常出錯(cuò)合砂,拋出ConcurrentModificationException異常,說我們?cè)诒闅v的時(shí)候還在修改元素源织。
- 這其實(shí)就是fail-fast機(jī)制~具體可參考博文:https://blog.csdn.net/panweiwei1994/article/details/77051261
區(qū)別有三點(diǎn):
- Iterator的方法名比Enumeration更科學(xué)
- Iterator有fail-fast機(jī)制翩伪,比Enumeration更安全
- Iterator能夠刪除元素,Enumeration并不能刪除元素
八谈息、ListIterator有什么特點(diǎn)
- ListIterator繼承了Iterator接口缘屹,它用于遍歷List集合的元素。
- ListIterator可以實(shí)現(xiàn)雙向遍歷,添加元素侠仇,設(shè)置元素
看一下源碼的方法就知道了:
九轻姿、并發(fā)集合類是什么?
Java1.5并發(fā)包(java.util.concurrent)包含線程安全集合類逻炊,允許在迭代時(shí)修改集合互亮。
- 迭代器被設(shè)計(jì)為fail-fast的,會(huì)拋出ConcurrentModificationException余素。
- 一部分類為:
- CopyOnWriteArrayList
- ConcurrentHashMap
- CopyOnWriteArraySet
十豹休、Java中HashMap的key值要是為類對(duì)象則該類需要滿足什么條件?
需要同時(shí)重寫該類的hashCode()方法和它的equals()方法桨吊。
- 從源碼可以得知威根,在插入元素的時(shí)候是先算出該對(duì)象的hashCode。如果hashcode相等話的视乐。那么表明該對(duì)象是存儲(chǔ)在同一個(gè)位置上的洛搀。
- 如果調(diào)用equals()方法,兩個(gè)key相同佑淀,則替換元素
- 如果調(diào)用equals()方法留美,兩個(gè)key不相同,則說明該hashCode僅僅是碰巧相同渣聚,此時(shí)是散列沖突独榴,將新增的元素放在桶子上
一般來說,我們會(huì)認(rèn)為:只要兩個(gè)對(duì)象的成員變量的值是相等的奕枝,那么我們就認(rèn)為這兩個(gè)對(duì)象是相等的棺榔!因?yàn)椋琌bject底層比較的是兩個(gè)對(duì)象的地址隘道,而對(duì)我們開發(fā)來說這樣的意義并不大~這也就為什么我們要重寫equals()
方法
重寫了equals()方法症歇,就要重寫hashCode()的方法郎笆。因?yàn)?strong>equals()認(rèn)定了這兩個(gè)對(duì)象相同,而同一個(gè)對(duì)象調(diào)用hashCode()方法時(shí)忘晤,是應(yīng)該返回相同的值的宛蚓!
十一、與Java集合框架相關(guān)的有哪些最好的實(shí)踐
- 根據(jù)需要確定集合的類型设塔。如果是單列的集合凄吏,我們考慮用Collection下的子接口ArrayList和Set。如果是映射闰蛔,我們就考慮使用Map~
- 確定完我們的集合類型痕钢,我們接下來確定使用該集合類型下的哪個(gè)子類~我認(rèn)為可以簡(jiǎn)單分成幾個(gè)步驟:
- 是否需要同步
- 去找線程安全的集合類使用
- 迭代時(shí)是否需要有序(插入順序有序)
- 去找Linked雙向列表結(jié)構(gòu)的
- 是否需要排序(自然順序或者手動(dòng)排序)
- 去找Tree紅黑樹類型的(JDK1.8)
- 是否需要同步
- 估算存放集合的數(shù)據(jù)量有多大,無論是List還是Map序六,它們實(shí)現(xiàn)動(dòng)態(tài)增長(zhǎng)任连,都是有性能消耗的。在初始集合的時(shí)候給出一個(gè)合理的容量會(huì)減少動(dòng)態(tài)增長(zhǎng)時(shí)的消耗~
- 使用泛型例诀,避免在運(yùn)行時(shí)出現(xiàn)ClassCastException
- 盡可能使用Collections工具類随抠,或者獲取只讀、同步或空的集合繁涂,而非編寫自己的實(shí)現(xiàn)拱她。它將會(huì)提供代碼重用性,它有著更好的穩(wěn)定性和可維護(hù)性
十二爆土、ArrayList集合加入1萬條數(shù)據(jù)椭懊,應(yīng)該怎么提高效率
ArrayList的默認(rèn)初始容量為10,要插入大量數(shù)據(jù)的時(shí)候需要不斷擴(kuò)容步势,而擴(kuò)容是非常影響性能的。因此背犯,現(xiàn)在明確了10萬條數(shù)據(jù)了坏瘩,我們可以直接在初始化的時(shí)候就設(shè)置ArrayList的容量!
這樣就可以提高效率了~
十三漠魏、總結(jié)
2018年4月15日17:14:03倔矾,上面找了一些面試題答了一下,感覺不夠過癮呀柱锹。很多我覺得比較重要的知識(shí)點(diǎn)我都沒有找到對(duì)應(yīng)的面試題(可能我搜索的能力太水了哪自?)。
將這篇文章作為集合的總結(jié)篇禁熏,但覺得沒什么好寫就回答一些面試題去了壤巷,找了一會(huì)面試題又覺得不夠系統(tǒng)。而這篇總結(jié)我又不想復(fù)制前面的章節(jié)總結(jié)到這里來瞧毙。于是我決定畫一個(gè)腦圖來結(jié)束這篇文章胧华!
2018年4月15日19:31:33 畫完啦<闹ⅰ!>囟S星伞!
需要更多腦圖的同學(xué)可關(guān)注公眾號(hào):Java3y悲没,回復(fù)【腦圖】即可~
如果文章有錯(cuò)的地方歡迎指正篮迎,大家互相交流。習(xí)慣在微信看技術(shù)文章示姿,想要獲取更多的Java資源的同學(xué)柑潦,可以關(guān)注微信公眾號(hào):Java3y。為了大家方便峻凫,剛新建了一下qq群:742919422渗鬼,大家也可以去交流交流。謝謝支持了荧琼!希望能多介紹給其他有需要的朋友
文章的目錄導(dǎo)航:https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
目前初步打算寫多線程譬胎,你們覺得怎么樣呢?可以在評(píng)論區(qū)留言~