當(dāng)前位置:首頁(yè) > IT技術(shù) > 編程語(yǔ)言 > 正文

面試題-Java集合
2022-02-14 14:06:10

1. 常見(jiàn)的集合有哪些?

  • 答案
    • Collection接口的子接口包括:Set接口和List接口

    • Map接口的實(shí)現(xiàn)類主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等

    • Set接口的實(shí)現(xiàn)類主要有:HashSet、TreeSet、LinkedHashSet等

    • List接口的實(shí)現(xiàn)類主要有:ArrayList、LinkedList、Stack以及Vector等


2. 常見(jiàn)的集合底層實(shí)現(xiàn)

  • 答案

    ArrayList底層是數(shù)組。

    LinkedList底層是雙向鏈表。

    HashMap底層與HashTable原理相同,Java 8版本以后如果同一位置哈希沖突大于8則鏈表變成紅黑樹(shù)。

    HashTable底層是鏈地址法組成的哈希表(即數(shù)組+單項(xiàng)鏈表組成)。

    HashSet底層是HashMap。

    LinkedHashMap底層修改自HashMap,包含一個(gè)維護(hù)插入順序的雙向鏈表。

    TreeMap底層是紅黑樹(shù)。

    LinkedHashSet底層是LinkedHashMap。

    TreeSet底層是TreeMap。


3. HashMap與HashTable的區(qū)別?

  • 答案

    HashMap沒(méi)有考慮同步,是線程不安全的;Hashtable使用了synchronized關(guān)鍵字,是線程安全的;

    HashMap允許K / V都為null;后者K / V都不允許為null。


4. ConcurrentHashMap和Hashtable的區(qū)別?

  • 答案

    ConcurrentHashMap結(jié)合了HashMap和HashTable二者的優(yōu)勢(shì)。HashMap沒(méi)有考慮同步,HashTable考慮了同步的問(wèn)題。但是HashTable在每次同步執(zhí)行時(shí)都要鎖住整個(gè)結(jié)構(gòu)。ConcurrentHashMap鎖的方式是稍微細(xì)粒度的。


5. ConcurrentHashMap實(shí)現(xiàn)原理

  • 答案

    **JDK1.7 : 【數(shù)組(Segment) + 數(shù)組(HashEntry) + 鏈表(HashEntry節(jié)點(diǎn))】
    **ConcurrentHashMap(分段鎖) 對(duì)整個(gè)桶數(shù)組進(jìn)行了分割分段(Segment),每一把鎖只鎖容器其中一部分?jǐn)?shù)據(jù),多線程訪問(wèn)容器里不同數(shù)據(jù)段的數(shù)據(jù),就不會(huì)存在鎖競(jìng)爭(zhēng),提高并發(fā)訪問(wèn)率。

    Segment是一種可重入鎖ReentrantLock,在ConcurrentHashMap里扮演鎖的角色,
    HashEntry則用于存儲(chǔ)鍵值對(duì)數(shù)據(jù)。

    JDK1.8 : Node數(shù)組+鏈表 / 紅黑樹(shù)
    利用CAS+Synchronized
    來(lái)保證并發(fā)更新的安全,底層依然采用數(shù)組+鏈表+紅黑樹(shù)的存儲(chǔ)結(jié)構(gòu)。


6. ArrayList和Vector的區(qū)別?

  • 答案

    Vector是線程安全的,ArrayList是線程不安全的。

    Vector在數(shù)據(jù)滿時(shí)增長(zhǎng)為原來(lái)的兩倍,而ArrayList在數(shù)據(jù)量達(dá)到容量的一半時(shí),增長(zhǎng)為原容量的1.5倍。


7. ArrayList和LinkedList的區(qū)別?

  • 答案

    LinkedList基于雙向鏈表的數(shù)據(jù)結(jié)構(gòu);ArrayList基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)。

    LinkedList在插入和刪除數(shù)據(jù)時(shí)效率更高,ArrayList查詢效率更高。


8. HashMap默認(rèn)的初始化長(zhǎng)度是多少?

  • 答案

    在JDK中默認(rèn)長(zhǎng)度是16,并且默認(rèn)長(zhǎng)度和擴(kuò)容后的長(zhǎng)度都必須是2的冪。


9. 談?wù)剬?duì)HashMap構(gòu)造方法中初始容量、加載因子的理解

  • 答案

    初始容量代表了哈希表中桶的初始數(shù)量,即Entry<K,V>[] table數(shù)組的初始長(zhǎng)度。

    加載因子是哈希表在其容量自動(dòng)增加之前可以達(dá)到多滿的一種飽和度百分比,其衡量了一個(gè)散列表的空間的使用程度,負(fù)載因子越大表示散列表的裝填程度越高,反之愈小。


10. Java集合框架是什么?說(shuō)出一些集合框架的優(yōu)點(diǎn)?

  • 答案

    每種編程語(yǔ)言中都有集合,最初的Java版本包含幾種集合類:Vector、Stack、HashTable和Array。隨著集合的廣泛使用,Java1.2提出了囊括所有集合接口、實(shí)現(xiàn)和算法的集合框架。在保證線程安全的情況下使用泛型和并發(fā)集合類,Java已經(jīng)經(jīng)歷了很久。它還包括在Java并發(fā)包中,阻塞接口以及它們的實(shí)現(xiàn)。集合框架的部分優(yōu)點(diǎn)如下:
    (1)使用核心集合類降低開(kāi)發(fā)成本,而非實(shí)現(xiàn)我們自己的集合類。
    (2)隨著使用經(jīng)過(guò)嚴(yán)格測(cè)試的集合框架類,代碼質(zhì)量會(huì)得到提高。
    (3)通過(guò)使用JDK附帶的集合類,可以降低代碼維護(hù)成本。
    (4)復(fù)用性和可操作性


11. 集合框架中的泛型有什么優(yōu)點(diǎn)?

  • 答案

    Java1.5引入了泛型,所有的集合接口和實(shí)現(xiàn)都大量地使用它。泛型允許我們?yōu)榧咸峁┮粋€(gè)可以容納的對(duì)象類型,因此,如果你添加其它類型的任何元素,它會(huì)在編譯時(shí)報(bào)錯(cuò)。這避免了在運(yùn)行時(shí)出現(xiàn)ClassCastException,因?yàn)槟銓?huì)在編譯時(shí)得到報(bào)錯(cuò)信息。泛型也使得代碼整潔,我們不需要使用顯式轉(zhuǎn)換和instanceOf操作符。它也給運(yùn)行時(shí)帶來(lái)好處,因?yàn)椴粫?huì)產(chǎn)生類型檢查的字節(jié)碼指令。


12. 為何Collection不從Cloneable和Serializable接口繼承?

  • 答案

    Collection接口指定一組對(duì)象,對(duì)象即為它的元素。如何維護(hù)這些元素由Collection的具體實(shí)現(xiàn)決定。例如,一些如List的Collection實(shí)現(xiàn)允許重復(fù)的元素,而其它的如Set就不允許。很多Collection實(shí)現(xiàn)有一個(gè)公有的clone方法。然而,把它放到集合的所有實(shí)現(xiàn)中也是沒(méi)有意義的。這是因?yàn)镃ollection是一個(gè)抽象表現(xiàn)。重要的是實(shí)現(xiàn)。

    當(dāng)與具體實(shí)現(xiàn)打交道的時(shí)候,克隆或序列化的語(yǔ)義和含義才發(fā)揮作用。所以,具體實(shí)現(xiàn)應(yīng)該決定如何對(duì)它進(jìn)行克隆或序列化,或它是否可以被克隆或序列化。

    在所有的實(shí)現(xiàn)中授權(quán)克隆和序列化,最終導(dǎo)致更少的靈活性和更多的限制。特定的實(shí)現(xiàn)應(yīng)該決定它是否可以被克隆和序列化。


13. Iterator是什么?

  • 答案

    Iterator接口提供遍歷任何Collection的接口。我們可以從一個(gè)Collection中使用迭代器方法來(lái)獲取迭代器實(shí)例。迭代器取代了Java集合框架中的Enumeration。迭代器允許調(diào)用者在迭代過(guò)程中移除元素。


14. Iterator和Listiterator之間有什么區(qū)別?

  • 答案

    (1)我們可以使用Iterator來(lái)遍歷Set和List集合,而ListIterator只能遍歷List。

    (2)Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷。

    (3)ListIterator從Iterator接口繼承,然后添加了一些額外的功能,比如添加一個(gè)元素、替換一個(gè)元素、獲取前面或后面元素的索引位置。


15. fail-fast與fail-safe有什么區(qū)別?

  • 答案

    Iterator的fail-fast屬性與當(dāng)前的集合共同起作用,因此它不會(huì)受到集合中任何改動(dòng)的影響。Java.util包中的所有集合類都被設(shè)計(jì)為fail-fast的,而java.util.concurrent中的集合類都為fail-safe的。Fail-fast迭代器拋出ConcurrentModificationException,而fail-safe迭代器從不拋出ConcurrentModificationException。


16. hashCode()和equals()方法有何重要性?

  • 答案

    HashMap使用Key對(duì)象的hashCode()和equals()方法去決定key-value對(duì)的索引。當(dāng)我們?cè)囍鴱腍ashMap中獲取值的時(shí)候,這些方法也會(huì)被用到。如果這些方法沒(méi)有被正確地實(shí)現(xiàn),在這種情況下,兩個(gè)不同Key也許會(huì)產(chǎn)生相同的hashCode()和equals()輸出,HashMap將會(huì)認(rèn)為它們是相同的,然后覆蓋它們,而非把它們存儲(chǔ)到不同的地方。同樣的,所有不允許存儲(chǔ)重復(fù)數(shù)據(jù)的集合類都使用hashCode()和equals()去查找重復(fù),所以正確實(shí)現(xiàn)它們非常重要。
    equals()和hashCode()的實(shí)現(xiàn)應(yīng)該遵循以下規(guī)則:

    (1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()總是為true的。

    (2)如果o1.hashCode() == o2.hashCode(),并不意味著o1.equals(o2)會(huì)為true。


17. 我們能否使用任何類作為Map的key?

  • 答案

    我們可以使用任何類作為Map的key,然而在使用它們之前,需要考慮以下幾點(diǎn):

    1. 如果類重寫了equals()方法,它也應(yīng)該重寫hashCode()方法。

    2. 類的所有實(shí)例需要遵循與equals()和hashCode()相關(guān)的規(guī)則。請(qǐng)參考之前提到的這些規(guī)則。

    3. 如果一個(gè)類沒(méi)有使用equals(),你不應(yīng)該在hashCode()中使用它。

    4. 用戶自定義key類的最佳實(shí)踐是使之為不可變的,這樣,hashCode()值可以被緩存起來(lái),擁有更好的性能。不可變的類也可以確保hashCode()和equals()在未來(lái)不會(huì)改變,這樣就會(huì)解決與可變相關(guān)的問(wèn)題了。


18. 如何決定選用HashMap還是TreeMap?

  • 答案

    對(duì)于在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。然而,假如你需要對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap是更好的選擇?;谀愕腸ollection的大小,也許向HashMap中添加元素會(huì)更快,將map換為TreeMap進(jìn)行有序key的遍歷。


19. 哪些集合類提供對(duì)元素的隨機(jī)訪問(wèn)?

  • 答案

    ArrayList、HashMap、TreeMap和HashTable類提供對(duì)元素的隨機(jī)訪問(wèn)。


20. BlockingQueue是什么?

強(qiáng)引用
這種引用屬于最普通最強(qiáng)硬的一種存在,只有在和 GC Roots 斷絕關(guān)系時(shí),才會(huì)被消掉。
軟引用
軟引用用于維護(hù)一些可有可無(wú)的對(duì)象。在內(nèi)存足夠的時(shí)候,軟引用對(duì)象不會(huì)被回收,只有在內(nèi)
存不足時(shí),系統(tǒng)則會(huì)回收軟引用對(duì)象,如果回收了軟引用對(duì)象之后仍然沒(méi)有足夠的內(nèi)存,才會(huì)
拋出內(nèi)存溢出異常。
可以看到,這種特性非常適合用在緩存技術(shù)上。比如網(wǎng)頁(yè)緩存、圖片緩存等。
軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾
回收,Java 虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
弱引用
弱引用對(duì)象相比較軟引用,要更加無(wú)用一些,它擁有更短的生命周期。當(dāng)JVM進(jìn)行垃圾回收
時(shí),無(wú)論內(nèi)存是否充足,都會(huì)回收被弱引用關(guān)聯(lián)的對(duì)象。弱引用擁有更短的生命周期,在 Java
中,用 java.lang.ref.WeakReference 類來(lái)表示。它的應(yīng)用場(chǎng)景和軟引用類似,可以在一些對(duì)
內(nèi)存更加敏感的系統(tǒng)里采用。
虛引用
這是一種形同虛設(shè)的引用,在現(xiàn)實(shí)場(chǎng)景中用的不是很多。虛引用必須和引用隊(duì)列
(ReferenceQueue)聯(lián)合使用。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一
樣,在任何時(shí)候都可能被垃圾回收。實(shí)際上,虛引用的 get,總是返回 null。

Java.util.concurrent.BlockingQueue是一個(gè)隊(duì)列,在進(jìn)行檢索或移除一個(gè)元素的時(shí)候,它會(huì)等待隊(duì)列變?yōu)榉强眨划?dāng)在添加一個(gè)元素時(shí),它會(huì)等待隊(duì)列中的可用空間。BlockingQueue接口是Java集合框架的一部分,主要用于實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式。我們不需要擔(dān)心等待生產(chǎn)者有可用的空間,或消費(fèi)者有可用的對(duì)象,因?yàn)樗荚贐lockingQueue的實(shí)現(xiàn)類中被處理了。

Java提供了集中BlockingQueue的實(shí)現(xiàn),比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等。

經(jīng)常和線程池中的workQueue夢(mèng)幻聯(lián)動(dòng)。


21. Collections類是什么?

  • 答案

    Java.util.Collections是一個(gè)工具類僅包含靜態(tài)方法,它們操作或返回集合。它包含操作集合的多態(tài)算法,返回一個(gè)由指定集合支持的新集合和其它一些內(nèi)容。這個(gè)類包含集合框架算法的方法,比如折半搜索、排序、混編和逆序等。


22. Comparable和Comparator接口有何區(qū)別?

  • 答案

    Comparable和Comparator接口被用來(lái)對(duì)對(duì)象集合或者數(shù)組進(jìn)行排序。

    Comparable接口被用來(lái)提供對(duì)象的自然排序,我們可以使用它來(lái)提供基于單個(gè)邏輯的排序。
    Comparable接口實(shí)際上是出自java.lang包,它有一個(gè)compareTo(Object obj)方法用來(lái)排序。

    Comparator接口被用來(lái)提供不同的排序算法,我們可以選擇需要使用的Comparator來(lái)對(duì)給定的對(duì)象集合進(jìn)行排序。
    Comparator接口實(shí)際上是出自java.util包,它有一個(gè)compare(Object obj1, Object obj2)方法用來(lái)排序。


本文摘自 :https://www.cnblogs.com/

開(kāi)通會(huì)員,享受整站包年服務(wù)立即開(kāi)通 >