Java Collections框架是Java編程語言的核心API之一肛走。
這是Java面試問題的重要主題之一。在這里,我列出了一些重要的Java集合面試問題和解答州弟,以幫助您進(jìn)行面試。這直接來自我14年以上的Java編程經(jīng)驗(yàn)。
1婆翔、Java 8中與Collections相關(guān)的功能是什么拯杠?
Java 8對 Collection API 進(jìn)行了重大更改。一些更改是:
- Java Stream API 用于集合類啃奴,以支持順序處理和并行處理
- Iterable 接口中的默認(rèn)方法forEach()潭陪,可用于迭代集合。與 lambda 表達(dá)式一起使用時(shí)最蕾,它非常有用依溯,因?yàn)槠鋮?shù) Consumer 是函數(shù)接口。
- Collections API 改進(jìn)瘟则,如在
Iterator
接口中的forEachRemaining(Consumer action)
黎炉,MapreplaceAll()
,compute()
壹粟,merge()
方法拜隧。
2、什么是 Java Collections Framework趁仙?列出 Collections 框架的一些好處洪添?
每個(gè)編程語言都使用集合,和最初的Java版本包含幾個(gè)集合類:Vector雀费,Stack干奢,Hashtable和Array。但是從較高的范圍和用法來看盏袄,Java 1.2提出了Collections Framework忿峻,該框架將所有collections接口,實(shí)現(xiàn)和算法分組辕羽。
Java的集合通過使用泛型和并發(fā)集合類進(jìn)行線程安全操作已經(jīng)走了很長一段路逛尚。它還包括在Java的并發(fā)包中的阻塞接口及其實(shí)現(xiàn)。
Collections 框架的一些好處是刁愿;
- 通過使用核心集合類而不是實(shí)現(xiàn)我們自己的集合類來減少開發(fā)工作绰寞。
- 通過使用通過良好測試的集合框架類,可以提高代碼質(zhì)量铣口。
- 通過使用JDK附帶的集合類滤钱,減少了代碼維護(hù)工作。
- 可重用性和互操作性
3脑题、集合框架中泛型的好處是什么件缸?
Java 1.5帶有泛型,所有集合接口和實(shí)現(xiàn)都大量使用它叔遂。泛型允許我們提供集合可以包含的Object的類型他炊,因此争剿,如果您嘗試添加其他類型的任何元素,則引發(fā)編譯時(shí)錯(cuò)誤佑稠。
這樣可以避免在運(yùn)行時(shí)發(fā)生ClassCastException秒梅,因?yàn)槟鷮⒃诰幾g時(shí)收到錯(cuò)誤。由于我們不需要使用強(qiáng)制轉(zhuǎn)換和實(shí)例化運(yùn)算符舌胶,因此泛型也使代碼更干凈捆蜀。
4、Java Collections Framework的基本接口是什么幔嫂?
Collection 表示集合層次結(jié)構(gòu)的根辆它。Collection表示一組元素的對象。Java平臺(tái)不提供此接口的任何直接實(shí)現(xiàn)履恩。
Set是一個(gè)不能包含重復(fù)元素的集合锰茉。此接口對數(shù)學(xué)集合的抽象進(jìn)行建模,并表示集合切心,例如紙牌集合垂券。
List是一個(gè)有序的集合趾代,可以包含重復(fù)的元素。您可以從其索引訪問任何元素。該列表更像是具有動(dòng)態(tài)長度的數(shù)組届囚。
一個(gè)Map是鍵映射到值的對象缩宜。映射不能包含重復(fù)的鍵:每個(gè)鍵最多可以映射到一個(gè)值的猛。
其他一些接口Queue
安皱,Dequeue
,Iterator
认然,SortedSet
补憾,SortedMap
和ListIterator
。
5卷员、為什么Collection不實(shí)現(xiàn)Cloneable和Serializable接口盈匾?
Collection接口指定為一組元素對象。元素的維護(hù)方式取決于Collection的具體實(shí)現(xiàn)毕骡。例如威酒,某些Collection實(shí)現(xiàn)(例如List)允許重復(fù)元素,而其他實(shí)現(xiàn)(例如Set)則不允許重復(fù)元素挺峡。
許多Collection實(shí)現(xiàn)都有Cloneable方法。但是担钮,將其包含在Collection的所有實(shí)現(xiàn)中沒有意義橱赠。這是因?yàn)镃ollection是抽象表示。重要的是箫津。
在處理實(shí)際實(shí)現(xiàn)時(shí)狭姨,克隆或序列化的語義及其含義都會(huì)發(fā)揮作用宰啦。因此具體的實(shí)現(xiàn)應(yīng)決定如何克隆或序列化它,甚至可以對其進(jìn)行克隆或序列化饼拍。
因此赡模,在所有實(shí)現(xiàn)中強(qiáng)制進(jìn)行克隆和序列化的靈活性較差,限制也更大师抄。具體實(shí)現(xiàn)應(yīng)決定是否可以克隆或序列化漓柑。
6、為什么Map接口沒有實(shí)現(xiàn)Collection接口叨吮?
盡管Map接口及其實(shí)現(xiàn)是Collections Framework的一部分辆布,但Map不是集合,集合也不是Map茶鉴。因此锋玲,Map擴(kuò)展Collection是沒有意義的,反之亦然涵叮。
如果Map擴(kuò)展了Collection接口惭蹂,那么元素在哪里?該映射包含key-value對割粮,并且提供了一些方法來檢索鍵或值的列表作為Collection盾碗,但它不適合“元素組”范式。
7穆刻、什么是迭代器置尔?
迭代器接口提供了對任何Collection進(jìn)行迭代的方法。我們可以使用iterator()方法從Collection中獲取迭代器實(shí)例氢伟。在Java Collections Framework中榜轿,迭代器代替了枚舉。迭代器允許調(diào)用者在迭代過程中從基礎(chǔ)集合中刪除元素朵锣。Java Collection迭代器提供了遍歷集合元素的通用方法谬盐,并實(shí)現(xiàn)了Iterator Design Pattern。
8诚些、Enumeration和Iterator接口之間有什么區(qū)別飞傀?
枚舉的速度是Iterator的兩倍,并且使用的內(nèi)存更少诬烹。枚舉是非吃曳常基本的,適合基本需求绞吁。但是幢痘,與Enumeration相比,Iterator安全得多家破,因?yàn)樗冀K拒絕其他線程修改被其迭代的集合對象颜说。
在Java Collections Framework中购岗,迭代器代替了枚舉。迭代器允許調(diào)用者從基礎(chǔ)集合中刪除Enumeration無法實(shí)現(xiàn)的元素门粪。迭代器方法名稱已得到改進(jìn)喊积,以使其功能更清晰。
9玄妈、為什么沒有像Iterator.add()這樣的方法將元素添加到集合中乾吻?
考慮到Iterator的約定不保證迭代順序,原因尚不清楚措近。但是請注意溶弟,ListIterator確實(shí)提供了add操作,因?yàn)樗_實(shí)保證了迭代的順序瞭郑。
10辜御、為什么Iterator沒有不移動(dòng)光標(biāo)就直接獲取下一個(gè)元素的方法?
可以在當(dāng)前Iterator接口的頂部實(shí)現(xiàn)它屈张,但是由于很少使用它擒权,因此將它包含在每個(gè)人都必須實(shí)現(xiàn)的接口中沒有意義。
11阁谆、Iterator和ListIterator有什么區(qū)別碳抄?
- 我們可以使用Iterator遍歷Set和List集合,而ListIterator只能與Lists一起使用场绿。
- Iterator只能向前移動(dòng)剖效,而ListIterator可以用于兩個(gè)方向。
- ListIterator繼承自Iterator接口焰盗,并具有其他功能璧尸,例如添加元素,替換元素熬拒,獲取上一個(gè)和下一個(gè)元素的索引位置爷光。
12、有哪些不同的方法可以遍歷列表澎粟?
我們可以通過兩種不同的方式遍歷列表-使用迭代器和使用for-each循環(huán)蛀序。
List <String> strList = new ArrayList<>();
for(String obj:strList){
System.out.println(obj);
}
Iterator<String> it= strList.iterator();
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
}
使用迭代器更加線程安全,因?yàn)樗梢源_保如果基礎(chǔ)列表元素被修改活烙,它將拋出異常ConcurrentModificationException
徐裸。
13、您對Iterator fail-fast屬性有什么了解啸盏?
每當(dāng)我們嘗試獲取下一個(gè)元素時(shí)重贺,迭代器fail-fast屬性都會(huì)檢查基礎(chǔ)集合的結(jié)構(gòu)是否有任何修改。如果找到任何修改,則拋出ConcurrentModificationException
檬姥。除了并行并發(fā)類(例如ConcurrentHashMap和CopyOnWriteArrayList)之外,Collection類中Iterator的所有實(shí)現(xiàn)在設(shè)計(jì)上都是fail-fast的粉怕。
14健民、fail-fast和fail-safe之間有何區(qū)別?
Iterato fail-safe屬性可與基礎(chǔ)集合的克隆一起使用贫贝,因此不受集合中任何修改的影響秉犹。按照設(shè)計(jì),java.util
包中的所有集合類都是fail-fast的稚晚,而其中的集合類java.util.concurrent
是fail-safe的崇堵。
fail-fast迭代器會(huì)拋出ConcurrentModificationException,而fail-safe迭代器絕不會(huì)拋出ConcurrentModificationException客燕。
15鸳劳、如何在迭代集合時(shí)避免ConcurrentModificationException?
我們可以使用并發(fā)集合類來避免ConcurrentModificationException
在集合上進(jìn)行迭代也搓,例如使用CopyOnWriteArrayList而不是ArrayList赏廓。
16、為什么沒有Iterator接口的具體實(shí)現(xiàn)傍妒?
Iterator接口聲明了用于迭代集合的方法幔摸,但是其實(shí)現(xiàn)是Collection實(shí)現(xiàn)類的責(zé)任。每個(gè)返回迭代器以進(jìn)行遍歷的集合類都有其自己的Iterator實(shí)現(xiàn)嵌套類颤练。
這使集合類可以選擇迭代器是fail-fast還是fail-safe的既忆。例如,ArrayList迭代器是fail-fast的嗦玖,而CopyOnWriteArrayList迭代器是fail-safe的患雇。
17、什么是UnsupportedOperationException踏揣?
UnsupportedOperationException
是用于指示不支持該操作的異常庆亡。它廣泛用于在JDK類,在集合框架java.util.Collections.UnmodifiableCollection
拋出該異常所有add
和remove
操作捞稿。
18又谋、HashMap如何在Java中工作?
HashMap在Map.Entry
靜態(tài)嵌套類實(shí)現(xiàn)中存儲(chǔ)鍵值對娱局。HashMap使用哈希算法彰亥,并在put
和get
方法中使用hashCode()和equals()方法。
當(dāng)我們put
通過傳遞鍵值對來調(diào)用方法時(shí)衰齐,HashMap使用帶有哈希值的Key hashCode()來查找存儲(chǔ)鍵值對的索引任斋。該條目存儲(chǔ)在LinkedList中,因此耻涛,如果已經(jīng)存在一個(gè)條目废酷,則使用equals()方法檢查傳遞的鍵是否已存在瘟檩,如果是,它將覆蓋該值澈蟆,否則它將創(chuàng)建一個(gè)新條目并存儲(chǔ)此鍵值條目墨辛。
當(dāng)我們get
通過傳遞Key來調(diào)用method時(shí),它再次使用hashCode()在數(shù)組中找到索引趴俘,然后使用equals()方法找到正確的Entry并返回其值睹簇。下圖將清楚地解釋這些細(xì)節(jié)。
有關(guān)HashMap的其他重要信息是容量寥闪,負(fù)載因子太惠,閾值大小調(diào)整。HashMap的初始默認(rèn)容量為16疲憋,負(fù)載系數(shù)為0.75凿渊。閾值是容量乘以負(fù)載因子,并且如果Map大小大于閾值柜某,則每當(dāng)我們嘗試添加條目時(shí)嗽元,HashMap都會(huì)將Map的內(nèi)容重新映射為容量更大的新數(shù)組。容量始終是2的乘方喂击,因此剂癌,如果您知道需要存儲(chǔ)大量的鍵值對,例如在緩存數(shù)據(jù)庫中的數(shù)據(jù)時(shí)翰绊,最好使用正確的容量和負(fù)載因子來初始化HashMap佩谷。 。
19监嗜、hashCode()和equals()方法的重要性是什么谐檀?
HashMap使用Key對象的hashCode()和equals()方法來確定放置鍵值對的索引。當(dāng)我們嘗試從HashMap中獲取價(jià)值時(shí)裁奇,也會(huì)使用這些方法桐猬。如果這些方法的實(shí)現(xiàn)不正確,則兩個(gè)不同的Key可能會(huì)產(chǎn)生相同的hashCode()和equals()輸出刽肠,在這種情況下溃肪,HashMap不會(huì)考慮將它們存儲(chǔ)在不同的位置,而是將其覆蓋并覆蓋它們音五。
同樣惫撰,所有不存儲(chǔ)重復(fù)數(shù)據(jù)的集合類都使用hashCode()和equals()查找重復(fù)項(xiàng),因此正確實(shí)現(xiàn)它們非常重要躺涝。equals()和hashCode()的實(shí)現(xiàn)應(yīng)遵循以下規(guī)則厨钻。
- 如果
o1.equals(o2)
,那么o1.hashCode() == o2.hashCode()
應(yīng)該永遠(yuǎn)如此true
。 - 如果
o1.hashCode() == o2.hashCode
是真的夯膀,這并不意味著o1.equals(o2)
會(huì)true
诗充。
20、我們可以使用任何類作為Map鍵嗎诱建?
我們可以將任何類用作Map Key其障,但是在使用它們之前應(yīng)考慮以下幾點(diǎn)。
如果該類重寫equals()方法涂佃,則它也應(yīng)該重寫hashCode()方法。
對于所有實(shí)例蜈敢,該類應(yīng)遵循與equals()和hashCode()關(guān)聯(lián)的規(guī)則辜荠。這些規(guī)則請參考前面的問題。
如果equals()中未使用類字段抓狭,則不應(yīng)在hashCode()方法中使用它伯病。
-
用戶定義的鍵類的最佳實(shí)踐是使其不可變,以便可以將hashCode()值緩存起來以提高性能否过。不可變的類還確保hashCode()和equals()將來不會(huì)更改午笛,這將解決任何可變性問題。
例如苗桂,假設(shè)我有一個(gè)MyKey
用于HashMap鍵的類药磺。//傳遞的mykey name參數(shù)用于equals()和hashcode() MyKey key = new MyKey("Pankaj"); //假定hashCode=1234 myHashMap.put(key, "Value"); // 下面的代碼將更改equals()和hashcode()的key // 但是它的位置不會(huì)改變 key.setName("Amit"); //假定新的hashCode=7890 //下面將返回null,因?yàn)镠ashMap將嘗試查找鍵 //與存儲(chǔ)在同一索引中煤伟,但由于密鑰發(fā)生了變化癌佩, //不匹配,返回空便锨。 myHashMap.get(new MyKey("Pankaj"));
這就是為什么String和Integer大多用作HashMap鍵的原因围辙。
21、Map接口提供哪些不同的Collection視圖放案?
Map接口提供了三個(gè)集合視圖:
- Set <K> keySet():返回此映射中包含的鍵的Set視圖姚建。該集合由Map支持,因此對Map的更改會(huì)反映在集合中吱殉,反之亦然掸冤。如果在對集合進(jìn)行迭代時(shí)修改了映射(通過迭代器的remove操作除外),則迭代的結(jié)果不確定考婴。該集合支持元素刪除贩虾,該元素通過迭代器remove,Set.remove沥阱,removeAll缎罢,retainAll和clear操作從映射中刪除相應(yīng)的映射。它不支持add或addAll操作。
- Collection <V> values():返回此映射中包含的值的Collection視圖策精。集合由Map支持舰始,因此對Map的更改會(huì)反映在集合中,反之亦然咽袜。如果在對集合進(jìn)行迭代時(shí)修改了映射(通過迭代器的remove操作除外)丸卷,則迭代結(jié)果不確定。集合支持元素刪除询刹,該元素通過迭代器remove谜嫉,Collection.remove,removeAll凹联,retainAll和clear操作從映射中刪除相應(yīng)的映射沐兰。它不支持add或addAll操作。
- Set <Map.Entry <K蔽挠,V >> entrySet():返回此映射中包含的映射的Set視圖住闯。該集合由Map支持,因此對Map的更改會(huì)反映在集合中澳淑,反之亦然比原。如果在對集合進(jìn)行迭代時(shí)修改了映射(通過迭代器的remove操作或迭代器返回的映射條目上的setValue操作除外),則迭代的結(jié)果不確定杠巡。該集合支持元素刪除量窘,該元素通過迭代器remove,Set.remove氢拥,removeAll绑改,retainAll和clear操作從映射中刪除相應(yīng)的映射。它不支持add或addAll操作兄一。
“不積跬步厘线,無以至千里”,希望未來的你能:有夢為馬 隨處可棲出革!加油造壮,少年!
關(guān)注公眾號(hào):「Java 知己」骂束,每天更新Java知識(shí)哦耳璧,期待你的到來!
- 發(fā)送「Group」展箱,與 10 萬程序員一起進(jìn)步旨枯。
- 發(fā)送「面試」,領(lǐng)取BATJ面試資料混驰、面試視頻攻略攀隔。
- 發(fā)送「玩轉(zhuǎn)算法」皂贩,領(lǐng)取《玩轉(zhuǎn)算法》系列視頻教程。
- 千萬不要發(fā)送「1024」...