1. 程式人生 > >【搞定Java基礎】之集合類面試題整理

【搞定Java基礎】之集合類面試題整理

因為集合類在Java基礎知識中是非常重要的,也是面試中最常問到的,設計的問題也比較多,因此單獨拿出來做面試題的整理,方便自己複習,也希望給看到此篇文章的你帶來一定的幫助。文章內容均來自於網路,平時看到總結不錯的題目,就收集在此。持續更新.......

先推薦幾篇不錯的文章:

1、Java集合類詳解:https://blog.csdn.net/softwave/article/details/4166598


  • 集合類的基本框架

Java集合類框架圖

---| Collection

---| List:有儲存順序,可重複

             ---| ArrayList:陣列實現、查詢快、增刪慢

             ---| LinkedList:連結串列實現,增刪快,查詢慢

             ---| Vector:和ArrayList原理相同,但是執行緒安全,效率略低

---| Set:無儲存順序,不可重複

             ---| HashSet:雜湊表實現、執行緒不安全、存取速度快

             ---| TreeSet:紅黑樹實現、預設對元素進行了排序

             ---| LinkedHashSet:雜湊表和連結串列共同的實現、會儲存儲存順序

---| Map

---| HashMap:採用雜湊表實現、無序、可以存null

---| TreeMap:和TreeSet原理一樣、可以對鍵進行排序、需要使用Comparable或者Comparator進行比較排序

---| HashTable:雜湊表實現、執行緒同步、不可以存null


  • HashMap的工作原理是什麼?

HashMap內部是通過一個數組實現的,只是這個陣列比較特殊,數組裡儲存的元素是一個Entry實體(jdk 8為Node)。這個Entry實體主要包含 key、value 以及一個指向自身的next指標。

HashMap是基於hashing實現的,當我們進行put操作時,根據傳遞的key值得到它的hashcode,然後再用這個hashcode與陣列的長度進行模運算,得到一個int值,就是Entry要儲存在陣列的位置(下標);當通過get方法獲取指定key的值時,會根據這個key算出它的hash值(陣列下標),根據這個hash值獲取陣列下標對應的Entry,然後判斷Entry裡的key,hash值或者通過equals()比較是否與要查詢的相同,如果相同,返回value,否則的話,遍歷該連結串列(有可能就只有一個Entry,此時直接返回null),直到找到為止,否則返回null。

HashMap之所以在每個陣列元素儲存的是一個連結串列,是為了解決hash衝突問題,當兩個物件的hash值相等時,那麼一個位置肯定是放不下兩個值的,於是hashmap採用連結串列來解決這種衝突,hash值相等的兩個元素會形成一個連結串列。


  • HashMap與HashTable的區別是什麼?

1、HashTable基於Dictionary類,而HashMap是基於AbstractMap。Dictionary是任何可將鍵對映到相應值的類的抽象父類,而AbstractMap是基於Map介面的實現,它以最大限度地減少實現此介面所需的工作。(在java 8中我檢視原始碼發現Hashtable並沒有繼承Dictionary,而且裡面也沒有同步方法,是不是java 8中Hashtable不在同步的了?有沒有人解釋一下?)

2、HashMap的key和value都允許為null,而Hashtable的key和value都不允許為null。HashMap遇到key為null的時候,呼叫putForNullKey方法進行處理,而對value沒有處理;Hashtable遇到null,直接返回NullPointerException。

3、Hashtable是同步的,而HashMap是非同步的,但是我們也可以通過Collections.synchronizedMap(hashMap),使其實現同步。


  • CorrentHashMap的工作原理?

JDK 1.6版:

ConcurrenHashMap可以說是HashMap的升級版,ConcurrentHashMap是執行緒安全的,但是與Hashtablea相比,實現執行緒安全的方式不同。Hashtable是通過對hash表結構進行鎖定,是阻塞式的,當一個執行緒佔有這個鎖時,其他執行緒必須阻塞等待其釋放鎖。ConcurrentHashMap是採用分離鎖的方式,它並沒有對整個hash表進行鎖定,而是區域性鎖定,也就是說當一個執行緒佔有這個區域性鎖時,不影響其他執行緒對hash表其他地方的訪問。

具體實現: ConcurrentHashMap內部有一個Segment陣列, 該Segment物件可以充當鎖。Segment物件內部有一個HashEntry陣列,於是每個Segment可以守護若干個桶(HashEntry),每個桶又有可能是一個HashEntry連線起來的連結串列,儲存發生碰撞的元素。

每個ConcurrentHashMap在預設併發級下會建立包含16個Segment物件的陣列,每個陣列有若干個桶,當我們進行put方法時,通過hash方法對key進行計算,得到hash值,找到對應的segment,然後對該segment進行加鎖,然後呼叫segment的put方法進行儲存操作,此時其他執行緒就不能訪問當前的segment,但可以訪問其他的segment物件,不會發生阻塞等待。

JDK 1.8版 :

在jdk 8中,ConcurrentHashMap不再使用Segment分離鎖,而是採用一種樂觀鎖CAS演算法來實現同步問題,但其底層還是“陣列+連結串列->紅黑樹”的實現。


  • 遍歷一個List有哪些不同的方式?

    List<String> strList = new ArrayList<>();
    // 方法一:for-each
    for(String str:strList) {
        System.out.print(str);
    }

    // 方法二:use iterator 儘量使用這種 更安全(fail-fast)
    Iterator<String> it = strList.iterator();
    while(it.hasNext) {
        System.out.printf(it.next());
    }

  • fail-fast與fail-safe有什麼區別?

Iterator的fail-fast屬性與當前的集合共同起作用,因此它不會受到集合中任何改動的影響。Java.util包中的所有集合類都被設計為fail-fast的,而java.util.concurrent中的集合類都為fail-safe的。當檢測到正在遍歷的集合的結構被改變時,fail-fast迭代器丟擲ConcurrentModificationException,而fail-safe迭代器從不丟擲ConcurrentModificationException。


  • Array和ArrayList有何區別?什麼時候更適合用Array?

1、Array可以容納基本型別和物件,而ArrayList只能容納物件;

2、Array是指定大小的,而ArrayList大小是固定的。


  • HashSet的底層實現是什麼?

通過看原始碼知道HashSet的實現是依賴於HashMap的,HashSet的值都是儲存在HashMap中的。在HashSet的構造法中會初始化一個HashMap物件,HashSet不允許值重複,因此,HashSet的值是作為HashMap的key儲存在HashMap中的,當儲存的值已經存在時返回false。


  • LinkedHashMap的實現原理?

LinkedHashMap也是基於HashMap實現的,不同的是它定義了一個Entry header,這個header不是放在Table裡,它是額外獨立出來的。LinkedHashMap通過繼承hashMap中的Entry,並新增兩個屬性Entry before,after和header結合起來組成一個雙向連結串列,來實現按插入順序或訪問順序排序。LinkedHashMap定義了排序模式accessOrder,該屬性為boolean型變數,對於訪問順序,為true;對於插入順序,則為false。一般情況下,不必指定排序模式,其迭代順序即為預設為插入順序。


  • LinkedList和ArrayList的區別是什麼?

1、ArrayList是基於陣列實現,LinkedList是基於連結串列實現;

2、ArrayList在查詢時速度快,LinkedList在插入與刪除時更具優勢。


持續更新......