Java:集合,Collection介面框架圖
Java集合大致可分為Set、List和Map三種體系,其中Set代表無序、不可重複的集合;List代表有序、重複的集合;而Map則代表具有對映關係的集合。Java 5之後,增加了Queue體系集合,代表一種佇列集合實現。
Java集合框架主要由Collection和Map兩個根介面及其子介面、實現類組成。本文僅探討Collection介面及其子介面、實現類。
目錄
1. Collection介面繼承樹
2. Collection介面是Set、List和Queue介面的父介面,基本操作包括:
- add(Object o):增加元素
- addAll(Collection c):...
- clear():...
- contains(Object o):是否包含指定元素
- containsAll(Collection c):是否包含集合c中的所有元素
- iterator():返回Iterator物件,用於遍歷集合中的元素
- remove(Object o):移除元素
- removeAll(Collection c):相當於減集合c
- retainAll(Collection c):相當於求與c的交集
- size():返回元素個數
- toArray():把集合轉換為一個數組
3. Collection的遍歷可以使用Iterator介面或者是foreach迴圈來實現
4. Set子介面
Set集合不允許包含相同的元素,而判斷兩個物件是否相同則是根據equals方法。
4.1 HashSet類
HashSet類是Set介面的典型實現類。特點:
- 不能保證元素的排列順序,加入的元素要特別注意hashCode()方法的實現。
- HashSet不是同步的,多執行緒訪問同一步HashSet物件時,需要手工同步。
- 集合元素值可以是null。
4.2 LinkedHashSet類
LinkedHashSet類也是根據元素的hashCode值來決定元素的儲存位置,但它同時使用連結串列維護元素的次序。與HashSet相比,特點:
- 對集合迭代時,按增加順序返回元素。
- 效能略低於HashSet,因為需要維護元素的插入順序。但迭代訪問元素時會有好效能,因為它採用連結串列維護內部順序。
4.3 SortedSet介面及TreeSet實現類
TreeSet類是SortedSet介面的實現類。因為需要排序,所以效能肯定差於HashSet。與HashSet相比,額外增加的方法有:
- first():返回第一個元素
- last():返回最後一個元素
- lower(Object o):返回指定元素之前的元素
- higher(Obect o):返回指定元素之後的元素
- subSet(fromElement, toElement):返回子集合
可以定義比較器(Comparator)來實現自定義的排序。預設自然升序排序。
4.4 EnumSet類
EnumSet類是專為列舉類設計的集合類,EnumSet中的所有元素都必須是指定列舉型別的列舉值。《Effective Java》第32條,用EnumSet代替位域,示範:
// EnumSet - a modern replacement for bit fields - Page 160
import java.util.*;
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
// Any Set could be passed in, but EnumSet is clearly best
public void applyStyles(Set<Style> styles) {
// Body goes here
}
// Sample use
public static void main(String[] args) {
Text text = new Text();
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}
}
5. List子介面
List子介面是有序集合,所以與Set相比,增加了與索引位置相關的操作:
- add(int index, Object o):在指定位置插入元素
- addAll(int index, Collection c):...
- get(int index):取得指定位置元素
- indexOf(Obejct o):返回物件o在集合中第一次出現的位置
- lastIndexOf(Object o):...
- remove(int index):刪除並返回指定位置的元素
- set(int index, Object o):替換指定位置元素
- subList(int fromIndex, int endIndex):返回子集合
5.1 ArrayList和Vector實現類
- 這兩個類都是基於陣列實現的List類。
- ArrayList是執行緒不安全的,而Vector是執行緒安全的。但Vector的效能會比ArrayList低,且考慮到相容性的原因,有很多重複方法。
- Vector提供一個子類Stack,可以挺方便的模擬“棧”這種資料結構(LIFO,後進先出)。
結論:不推薦使用Vector類,即使需要考慮同步,即也可以通過其它方法實現。同樣我們也可以通過ArrayDeque類或LinkedList類實現“棧”的相關功能。所以Vector與子類Stack,建議放進歷史吧。
5.2 LinkedList類
不像ArrayList是基於陣列實現的線性表,LinkedList類是基於連結串列實現的。
另外還有固定長度的List:Arrays工具類的方法asList(Object... a)可以將陣列轉換為List集合,它是Arrays內部類ArrayList的例項,特點是不可以增加元素,也不可以刪除元素。
6. Queue子介面
Queue用於模擬佇列這種資料結構,實現“FIFO”等資料結構。通常,佇列不允許隨機訪問佇列中的元素。
Queue 介面並未定義阻塞佇列的方法,而這在併發程式設計中是很常見的。BlockingQueue 介面定義了那些等待元素出現或等待佇列中有可用空間的方法,這些方法擴充套件了此介面。
Queue 實現通常不允許插入 null 元素,儘管某些實現(如 LinkedList)並不禁止插入 null。即使在允許 null 的實現中,也不應該將 null 插入到 Queue 中,因為 null 也用作 poll 方法的一個特殊返回值,表明佇列不包含元素。
基本操作:
- boolean add(E e) : 將元素加入到隊尾,不建議使用
- boolean offer(E e): 將指定的元素插入此佇列(如果立即可行且不會違反容量限制),當使用有容量限制的佇列時,此方法通常要優於 add(E),後者可能無法插入元素,而只是丟擲一個異常。推薦使用此方法取代add
- E remove(): 獲取頭部元素並且刪除元素,不建議使用
- E poll(): 獲取頭部元素並且刪除元素,佇列為空返回null;推薦使用此方法取代remove
- E element(): 獲取但是不移除此佇列的頭
- E peek(): 獲取佇列頭部元素卻不刪除元素,佇列為空返回null
@Test public void testQueue() { Queue<String> queue = new LinkedList<String>(); queue.offer("1.你在哪兒?"); queue.offer("2.我在這裡。"); queue.offer("3.那你又在哪兒呢?"); String str = null; while ((str = queue.poll()) != null) { System.out.println(str); } }
6.1 PriorityQueue類
PriorityQueue儲存佇列元素的順序並不是按照加入佇列的順序,而是按佇列元素的大小重新排序。當呼叫peek()或者是poll()方法時,返回的是佇列中最小的元素。當然你可以與TreeSet一樣,可以自定義排序。自定義排序的一個示範:
@Test
public void testPriorityQueue() {
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(20, new Comparator<Integer>() {
public int compare(Integer i, Integer j) {
// 對數字進行奇偶分類,然後比較返回;偶數有較低的返回值(對2取餘數然後相減),奇數直接相減。
int result = i % 2 - j % 2;
if (result == 0)
result = i - j;
return result;
}
});
// 倒序插入測試資料
for (int i = 0; i < 20; i++) {
pq.offer(20 - i);
}
// 列印結果,偶數因為有較低的值,所以排在前面
for (int i = 0; i < 20; i++) {
System.out.println(pq.poll());
}
}
輸出:
2,4,6,8,10,12,14,16,18,20,1,3,5,7,9,11,13,15,17,19,
6.2 Deque子介面與ArrayDeque類
Deque代表一個雙端佇列,可以當作一個雙端佇列使用,也可以當作“棧”來使用,因為它包含出棧pop()與入棧push()方法。
ArrayDeque類為Deque的實現類,陣列方式實現。方法有:
- addFirst(Object o):元素增加至佇列開頭
- addLast(Object o):元素增加至佇列末尾
- poolFirst():獲取並刪除佇列第一個元素,佇列為空返回null
- poolLast():獲取並刪除佇列最後一個元素,佇列為空返回null
- pop():“棧”方法,出棧,相當於removeFirst()
- push(Object o):“棧”方法,入棧,相當於addFirst()
- removeFirst():獲取並刪除佇列第一個元素
- removeLast():獲取並刪除佇列最後一個元素
6.3 實現List介面與Deque介面的LinkedList類
LinkedList類是List介面的實現類,同時它也實現了Deque介面。因此它也可以當做一個雙端佇列來用,也可以當作“棧”來使用。並且,它是以連結串列的形式來實現的,這樣的結果是它的隨機訪問集合中的元素時效能較差,但插入與刪除操作效能非常出色。
7. 各種線性表選擇策略
- 陣列:是以一段連續記憶體儲存資料的;隨機訪問是最快的,但不支援插入、刪除、迭代等操作。
- ArrayList與ArrayDeque:以陣列實現;隨機訪問速度還行,插入、刪除、迭代操作速度一般;執行緒不安全。
- Vector:以陣列實現;隨機訪問速度一般,插入、刪除、迭代速度不太好;執行緒安全的。
- LinkedList:以連結串列實現;隨機訪問速度不太好,插入、刪除、迭代速度非常快。