《Java後端知識體系》系列之Java集合

爲了幾個月後的面試準備的湯姆!

先上集合知識圖譜:有不足的或者錯誤的地方歡迎下方評論指正!

在這裏插入圖片描述
集合

  • Collection

    • List
      • ArrayList:
        • 底層實現:底層是可變數組的數據結構,默認的初始化長度爲10,如果沒有設置容量默認是空數組,然後在進行add的時候會擴容到10(此時是創建了一個新的數組,然後將舊的數組複製到新數組中),後面擴容的話是按照0.5倍的大小進行擴容的,是線程不安全的,底層是數組所以查詢效率更高,新增、刪除效率低。
      • LinkedList
        • 底層實現:底層是雙向鏈表,地址是任意的,採用的是尾插法的的方式,在鏈表中有頭節點、尾節點、指針,所以在插入和刪除時不需要移動數據,所以效率高,但是查詢時需要通過指針來尋找數據,所以效率很低;也是線程不安全的。
      • Vector
        • 底層實現:底層也是數組實現的,結構跟ArrayList差不多,但是Vector是線程安全的,底層通過使用synchronized鎖維持線程安全,所以性能較低;Vector擴容時會擴容一倍(也就是擴容到當前容量的兩倍),同時在擴容時可以通過設置增長因子來設定擴容。
    • Set
      • HashSet
        • 底層實現:HashSet是通過哈希表實現的,HashSet中的數據是無序的,可以存入null值,但是隻能存入一個null,兩個數據中的值不允許重複,就如數據庫中的唯一約束;同時HashSet放入的對象必須實現hashcode方法,放入的對象都是以hashcode碼作爲唯一標識的。
      • TreeSet
        • 底層實現:TreeSet是通過紅黑樹實現的(底層繼承了TreeMap,TreeMap是通過紅黑樹來實現的),在TreeSet中存儲的是排好序的數據同時不允許有重複值,也是非線程安全的,效率上不如HashSet(二叉樹要進行旋轉消耗性能)
  • Map

    • TreeMap
      • 實現原理:TreeMap是通過紅黑樹來實現的(瞭解紅黑樹可以看這篇),紅黑樹是排好序的數據結構,是非線程安全的。
    • HashMap
      • 實現原理:HashMap的實現是通過數組+鏈表+紅黑樹(jdk1.8)非線程安全的,key可以爲null值,默認的負載因子爲0.75,在擴容時都是2的次冪(這是因爲擴大2的次冪的容量後,重新計算數據的hash值的時候只會影響最高位的數據,這樣就減少了重新分配位置的操作,提高了效率。可以看我這篇對源碼的分析)。HashMap中當鏈表的長度大於等於8的時候(同時數組長度大於64不然只會進行擴容)會將鏈表轉換爲紅黑樹,同時當紅黑樹的長度小於6時,又會將紅黑樹轉換爲鏈表,在jdk1.8中採用了尾插法,這樣的做法解決了jdk1.7中頭插法的死循環問題.
    • HashTable
      • 實現原理:HashTable的實現原理跟HashMap類似,主要的區別在於HashTable是線程安全的,內部使用synchronized鎖實現線程安全,因爲使用synchronized所以性能比較差。
    • ConcurrentHashMap
      • 實現原理:ConcurrentHashMap是屬於JUC併發包的一種,屬於線程安全的結構,底層也是通過數組+鏈表+紅黑樹來實現的(jdk1.8),在ConcurrentHashMap的put方法中會根據hash值計算這個新插入的點在table中的位置i,如果位置i是空的,直接放進去,否則進行判斷,如果i位置是樹節點,按照樹的方式插入新的節點,否則把i插入到鏈表的末尾,同時不允許key或value爲null。對於多線程下的put存在兩種情況:
        • 如果一個或多個線程正在對ConcurrentHashMap進行擴容操作,當前線程也要進入擴容的操作中。這個擴容的操作之所以能被檢測到,是因爲transfer方法中在空結點上插入forward節點,如果檢測到需要插入的位置被forward節點佔有,就幫助進行擴容(在擴容時多線程會幫助進行擴容以及數據的遷移)。
        • 如果檢測到要插入的節點是非空且不是forward節點,就對這個節點加鎖,這樣就保證了線程安全。儘管這個有一些影響效率,但是還是會比hashTable的synchronized要好得多。

搞了兩個小時知識總結,我真是會敲代碼的湯姆貓!!

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