java面試題 --- 集合

1. java 集合你瞭解嗎?

  • java 集合最頂層接口是 Collection 和 Map;
  • Collection 有三個核心接口,分別是 List,Set,Queue;
  • List 是有序可重複的,它的主要實現類有 ArrayList、LinkedList 和 Vector;
  • ArrayList 是數組實現的,查詢快增刪慢線程不安全;
  • LinkedList 是鏈表實現的,查詢慢增刪快線程不安全;
  • Vector 相當於線程安全的 ArrayList;
  • Set 是無序不重複的,它的主要實現類有 HashSet、TreeSet 和 LinkedHashSet,它們分別是用對應的 Map 實現的,比如 HashSet 就是用 HashMap實現的,注意 TreeSet 是有序的;
  • Queue 是隊列,主要有阻塞隊列 BlockingQueue。Map 的主要實現類有 HashMap、LinkedHashMap、HashTable 和 TreeMap。

2. 什麼是集合的快速失敗機制?

  • 集合內部會維護一個 modCount 變量,遍歷的時候,會判斷 modCount 變量的值是否等於期望值,不等就會報併發修改異常。

3. 用 for 循環遍歷集合的同時移除元素可以嗎?

  • 不可以,會報併發修改異常。要邊遍歷邊移除元素,只能用迭代器。

4. HashMap 底層是用什麼實現的?

  • jdk1.7 的 HashMap 採用拉鍊法,數組加鏈表實現的;
  • jdk1.8 的 HashMap 採用了數組加鏈表加紅黑樹實現。

5. HashMap (jdk1.8) 怎麼初始化的?

  • 如果調用的是無參構造,不會立即初始化數組,要等 put 元素時纔會初始化一個長度爲 16 的數組;
  • 如果調用的是帶參構造,就會將數組長度初始化爲最接近傳入參數的 2 的 n 次冪,比如傳入的是 6,那就初始化爲 8。

6. HashMap (jdk1.8) 怎麼計算索引的?

  • 首先會對 key 的 hashCode 值的高十六位與低十六位做一個異或 (^) 運算,這樣做是爲了讓 key 的整個 hashCode 都能參與接下來的計算,減少 hash 碰撞的概率,且異或運算得到 0 和 1 的概率一樣,不會影響數據分佈;
  • 接着拿到剛纔計算出來的值,和數組長度減一之後的值進行與 (&) 運算,就得到了索引。

7. HashMap (jdk1.8) 計算索引時爲什麼用與 (&) 操作?

  • 正常情況計算索引應該是 hashCode 值對數組長度取模,即求餘,但是取模運算的效率不高,所以改用與 (&) 操作。

8. HashMap (jdk1.8) 數組長度爲什麼是 2 的 n 次冪?

  • 只有當數組長度爲 2 的 n 次冪時,hashCode 值與 (&) 數組長度減一的計算結果纔會和 hashCode 值對數組長度取模的計算結果纔會一致;
  • 同時 2 的 n 次冪減一的二進制是若干個 1,和奇數計算最後結果是奇數,和偶數計算的結果是偶數,如果最後一位是 0,那麼不管和奇數還是偶數進行與 (&) 計算的結果都是偶數,不能保證散列分佈均勻。

9. HashMap (jdk1.8) 計算拿到索引後直接把元素存在那個位置嗎?

  • 拿到索引後,先判斷索引位置是否有元素,如果沒有,直接把元素放到索引位置;
  • 如果有,判斷 key 是否一樣,如果一樣,新值覆蓋舊值;
  • 如果不一樣,就在此處生成鏈表,元素存到鏈表中。

10. HashMap (jdk1.8) 什麼時候生成紅黑樹?

  • 當鏈表長度達到 8,且數組長度達到 64 的時候,就會生成紅黑樹;
  • 當紅黑樹節點少於 6 個的時候,又會將紅黑樹轉回鏈表。

11. HashMap (jdk1.8) 數組什麼時候擴容?

  • 擴容因子是 0.75,當數組中元素個數達到數組長度的 3/4 時就擴容,擴容爲原來的兩倍。

12. HashMap (jdk1.8) 數組擴容後數據怎麼轉移?

  • 如果原先數組那位位置的元素是單個元素或者紅黑樹,那就放到 hash 與 (&) 新數組長度減一的位置;
  • 如果是鏈表,那就判斷 hash 與 (&) 舊數組長度是否爲 0,如果是,就放在原來索引處,如果不是,就放在原來索引加上舊數組長度處。

13. 既然 HashMap (jdk1.8) 不安全,那併發情況下用什麼?

  • 用 ConcurrentHashMap。

14. ConcurrentHashMap 的底層你知道嗎?

  • jdk1.7 的 ConcurrentHashMap 底層是 Segment 數組,Segment 數組存放的元素是 HashEntry 數組,HashEntry 數組存放的元素是鏈表。每次鎖住一個 Segment,保證安全性的同時提高了併發性,這就是鎖分段機制;
  • jdk1.8 的 ConcurrentHashMap 的底層是數組加鏈表加紅黑樹,用 Synchronized 和 CAS 來保證線程安全。

15. ArrayList 的 elementData 爲什麼用 transient 修飾?

  • 加上 transient 就不會直接序列化整個數組,序列化的時候只序列化數組中存的元素,而不是整個數組,既加快了序列化速度也減小了序列化後文件的大小。

16. List 和 Set 如何選用?

  • List 支持隨機快速訪問,支持用索引獲取元素,Set 不支持。所以如果增刪操作比較多,適合用 Set,查詢操作比較多,適合用 List;
  • List 是有序可重複的,而 Set 是無序不重複的。所以可以根據存入的元素是否需要順序、是否可以重複來決定用什麼。

17. HashSet 如何保證元素不重複?

  • HashSet 底層是 HashMap,HashSet 存儲的元素就存放在 HashMap 的 key 中,HashMap 的 key 是否相同是先比較 hashCode 值再用 equals 方法比較。

18. 爲什麼 String、Integer 適合作爲 HashMap 的 key?

  • 因爲 String 和 Integer 都是 final 類型的,能夠保證 hash 值的不可更改性;
  • String 和 Integer 已經重寫了 hashCode 方法和 equals 方法,可以保證計算的準確性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章