Java基礎知識總結 ——集合

1. List

List是有序的Collection,List一共有三個實現類:ArrayList、Vector和LinkedList。

1.1. ArrayList

ArrayList內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔,當數組大小不滿足時需要增加存儲能力,就要將已經有數組的數據複製到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,需要對數組進行復制、移動,代價比較高。因此他適合隨機查找和遍歷,不適合插入和刪除。

1.2. Vector

Vector和ArrayList一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。

1.3. LinkedList

LinkedList是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了List接口中沒有定義的方法,專門用於操作表頭和表尾元素,可以當做堆棧、隊列和雙向隊列使用。

2. Set

Set集合用於存儲無序元素,值不能重複。對象的相等性本質是對象hashCode值判斷的,如果想要讓兩個不同的對象視爲相等,就必須覆蓋Object的hashCode方法和equals方法。

2.1. HashSet

哈希表存放的是哈希值。HashSet存儲元素的順序並不是按照存入時的順序而是按照哈希值來存的,所以取數據也是按照哈希值取的。元素的哈希值是通過元素的hashCode方法來獲取的,HashSet首先判斷兩個元素的哈希值,如果哈希值一樣,接着會比較equals方法,如果equals結果爲true,HashSet就視爲同一個元素。如果equals爲false就不是同一個元素。
哈希值相同equals爲false的元素就是在同樣的哈希值下順延,哈希一樣的存一列。一個hashCode位置上可以存放多個元素。

2.2. TreeSet

TreeSet()是使用二叉樹的原理對新add()的對象按照指定的順序排序(升、降序),每增加一個對象都會進行排序,講對象插入二叉樹指定的位置。
Integer和String對象都可以進行默認的TreeSet排序,而自定義的對象是不可以的,自己定義的類必須實現Comparable接口,並且覆寫相對應的compareTo()函數,纔可以正常使用。
在覆寫compareTo()函數時,要返回相應的值才能使TreeSet按照一定的規則來排序。
比較此對象與指定對象的順序。如果該對象小於、等於或大於指定對象,則分別返回負整數、零或正整數。

2.3. LinkedHashSet(繼承HashSet)

對於LinkedHashSet而言,它繼承與HashSet又基於LinkedHashMap來實現的。LinkedHashSet底層使用LinkedHashMap來保存所有元素,它繼承與HashSet,其所有方法操作上又和HashSet相同,因此LinkedHashSet的實現上非常簡單,只提供了四個構造方法,並通過傳遞一個標識參數,調用父類的構造器,底層構造一個LinkedHashMap來實現,在相關操作上與父類HashSet的操作相同,直接調用父類的HashSet的方法即可。

3. Queue

4. HashMap

HashMap根據鍵的hashCode值存儲數據,大多數情況下可以直接定位到它的值,因而具有很快的訪問速度,但遍歷順序卻是不確定的。HashMap最多隻允許一條記錄的鍵爲null,允許多條記錄的值爲null。HashMap非線程安全,即任一時刻可以有多個線程同時寫HashMap,可能會導致數據的不一致。如果需要滿足線程安全,可以用Collections的synchronizedMap方法使HashMap具有線程安全的能力,或者使用ConcurrentHashMap。HashMap的結構如下圖:
在這裏插入圖片描述
HashMap裏面是一個數組,然後數組中每個元素時一個單向鏈表。圖中每個綠色的屍體是嵌套類Entry的實例,Entry包含四個屬性:key,value,hash值和用於單向鏈表的next。
(1)capacity:當前數組容量,始終保持2^n,可以擴容,擴容後數組大小爲當前的2倍。
(2)loadFactor:負載因子,默認爲0.75
(3)threshold:擴容的閥值,等於capacity*loadFactor

Java8對HashMap進行了一些修改,最大的不同就是利用了紅黑樹,所以其由數組+鏈表+紅黑樹組成。
根據Java7 HashMap的介紹,我們知道,查找的時候,根據hash值我們能夠快速定位到數組的具體下標,但是之後的話,需要順着鏈表一個個比較下去才能找到我們需要的,時間複雜度取決於鏈表的長度,爲O(n)。爲了降低這部分的開銷,在Java8中,當鏈表中的元素超過了8個以後,會講鏈表轉換爲紅黑樹,在這些位置進行查找的時候可以降低時間複雜度爲O(logN)。
在這裏插入圖片描述

4.1. LinkedHashMap

LinkedHashMap是HashMap的一個子類,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時帶參數,按照訪問次序排序。

5. HashTable

HashTable是遺留類,很多映射的常用功能與HashMap類似,不同的是它承自Dictionary類,並且是線程安全的,任一時間只有一個線程能寫HashTable,併發性不如ConcurrentHashMap,因爲ConcurrentHashMap引入了分段鎖。HashTable不建議在新代碼中使用,不需要線程安全的場合可以用HashMap替換,需要線程安全的場合可以用ConcurrentHashMap替換。

6. TreeMap

TreeMap實現SortedMap接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator遍歷TreeMap時,得到的記錄是排序過的。如果使用排序的映射,建議使用TreeMap。
在使用TreeMap時,key必須實現Comparable接口或者在構造TreeMap傳入自定義的Comparator,否則會在運行時拋出 java.lang.ClassCastException 類型的異常。

7. ConcurrentHashMap

7.1. Segment段

ConcurrentHashMap由一個個Segment組成,Segment代表”部分“或”一段“的意思,所以很多地方會將其描述爲分段鎖。

7.2. 線程安全(Segment繼承ReentrantLock加鎖)

簡單理解就是,ConcurrentHashMap是一個Segment數組,Segment通過繼承ReentrantLock來進行加鎖,所以每次需要加鎖的操作鎖住的是一個Segment,這樣只要保證每個Segment是線程安全的,也就實現了全局的線程安全。
在這裏插入圖片描述

7.3. concurrencyLevel(默認 16)

concurrencyLevel可以翻譯爲並行級別、併發數、Segment數等。默認是16,也就是說ConcurrentHashMap有16個Segments,所以理論上,這個時候,最多可以同時支持16個線程併發寫,只要它們的操作分別分佈在不同的Segment上。這個值可以在初始化的時候設置爲其他值,但一旦初始化以後,它是不可擴容的。
Java8 對 ConcurrentHashMap 進行了比較大的改動,Java8 也引入了紅黑樹。

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