Java集合
Java中集合類主要用於保存、盛裝其他類型的數據,因此集合類也稱爲容器類。所有的集合類都位於java.util
包下,容器類只能保存引用類型。Java中的集合類主要有兩個接口:Collection
和Map
,本文主要討論Collection
接口。Collection
接口的繼承樹如下:
Set接口
- Set接口與Collection基本相同,沒有提供額外的方法
- Set接口的所有實現類都不允許包含重複元素
HashSet類
HashSet
按照哈希碼來存儲集合中的元素,因此具有很好的存取和查找性能。- 不保證元素的排列順序
- 不是線程安全的
- 元素值可以是
null
向HashSet中存入一個新元素時,HashSet會調用該對象的hashCode()
方法來得到該對象的哈希值,然後根據哈希值決定該對象在集合中的存儲位置。如果兩個元素equals()
方法返回true
,但是哈希值不等,仍然可以添加成功;反過來,如果兩個對象哈希值相同但是equals()
返回false
,也仍然可以添加成功。
如果需要把某個類型的對象保存到
HashSet
中,重寫該類的hashCode()
方法和equals()
方法時,儘量保證如果equals()
方法返回true
,那麼其哈希值也要相等。
由於HashSet
的存取和查找都是依賴於哈希值,因此在存儲可變對象時會有風險,如果修改HashSet集合中的對象,有可能導致該對象的哈希值變化,從而導致HashSet
無法準確訪問該對象。
HashSet
底層實現是基於HashMap
的,具體可參照HashMap
的實現。
LinkedHashSet類
LinkedHashSet
是HashSet
的子類,內部使用了一個鏈表維護了元素的插入順序,因此性能略低於HashSet
,但是在迭代時有很好的性能。
TreeSet類
TreeSet
是SortedSet
接口的實現類,可以確保集合元素處於排序狀態。支持兩種排序方法:
- 自然排序:直接調用元素的compareTo方法比較元素之間的大小(實現了Comparable接口的對象),然後將集合元素按升序排列
- 定製排序:在構造
TreeSet
實例時,提供一個Comparator
對象用於對元素進行比較。
Set接口性能分析
HashSet
的性能總是比TreeSet
好,因爲排序需要額外的開銷。LinkedHashSet
一般情況下比HashSet
略慢,但是在遍歷訪問時,LinkedHashSet
會更快。
List接口
List
接口根據整數索引訪問其中的元素。
ArrayList類和Vector類
-
相同點:
- 長度動態可變
- 內部用
Object[]
數組實現 - 不指定初始容量時,默認爲10;如果需要一次性添加大量元素,可使用
ensureCapacity(int minCapacity)
方法,減少重分配的次數提高性能。
-
不同點:
Vector
是線程安全的,而ArrayList
不是線程安全的Vector
的性能低於ArrayList
固定長度的List
Arrays.asList(Object... a)
方法可以把一個數組或一些對象轉換成一個List
集合,但是返回的是Arrays.ArrayList
的實例,其長度固定,只能遍歷訪問該集合裏的元素,不可增加、刪除。
Queue接口
- 用於模擬隊列,是一個“先進先出”(FIFO)的容器。
PriorityQueue實現類
- 即數據結構中“優先隊列”的實現
- 排序方式與
TreeSet
一致
Deque接口與ArrayDeque類
Deque
接口是Queue
接口的子接口,表示一個雙端隊列- 該接口有一個實現類
ArrayDeque
,用數組Object[]
實現
LinkedList實現類
- 內部用鏈表的像是保存集合中的元素
- 隨機訪問性能價差,插入刪除元素的性能較好
各種線性表的性能分析
List
接口是一種線性表接口,其不同的實現在不同的應用場景中有性能差異
- 如果需要遍歷集合元素,對於
ArrayList
對象和Vector
對象應該使用索引來訪問;而對於LinkedList
對象,應該採用迭代器來遍歷 - 如果需要經常執行插入、刪除操作,可考慮使用
LinkedList
。 - 如果有多個線程需要同時訪問
List
集合中的元素,可考慮使用Collections
將集合包裝成線程安全的。