集合基礎詳解
Iterable 介面
-
Iterable是一個超級介面,被Collection所繼承。它只有一個方法: Iterator
iterator() //即返回一個迭代器 -
Java中的Iterator功能比較簡單,並且只能單向移動:
(1) 使用方法iterator()要求容器返回一個Iterator。第一次呼叫Iterator的next()方法時,它返回序列的第一個元素。注意:iterator()方法是java.lang.Iterable介面,被Collection繼承。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Collection 介面
JDK 不提供此介面的任何直接 實現:它提供更具體的子介面(如 Set 和 List)實現。
不同的Collection子類對於有序性、重複性、null、執行緒同步都有不同的策略。
List 介面
-
List是有序的 collection(也稱為序列)。此介面的使用者可以對列表中每個元素的插入位置進行精確地控制。使用者可以根據元素的整數索引(在列表中的位置)訪問元素,並搜尋列表中的元素。
-
使用者插入的順序或者指定的位置就是元素插入的位置。它與Set不同,List允許插入重複的值。
-
List 介面提供了特殊的迭代器,稱為 ListIterator,除了允許 Iterator 介面提供的正常操作外,該迭代器還允許元素插入
雙向訪問
。還提供了一個方法(如下)來獲取從列表中指定位置開始的列表迭代器。ListIterator <E> listIterator(int index) 返回列表中元素的列表迭代器(按適當順序),從列表的指定位置開始
-
List 介面提供了兩種搜尋指定物件的方法。從效能的觀點來看,應該小心使用這些方法。在很多實現中,它們將執行高開銷的線性搜尋。
-
List 介面提供了兩種在列表的任意位置高效插入和移除多個元素的方法。
List的子類
- List最流行的實現類有Vector、ArrayList、LinkedList。
1、 ArrayList (類)
- ArrayLis是基於陣列實現的List類,它封裝了一個動態的、增長的、允許再分配的
1.5倍
) - 當從ArrayList的中間位置插入或者刪除元素時,需要對陣列進行復制、移動、代價比較高。因此,它適合隨機查詢和遍歷,不適合插入和刪除。
2、Vector(類)
Vector與ArrayList一樣,也是通過陣列實現的,不同的是它支援執行緒的同步
,即某一時刻只有一個執行緒能夠寫Vector,避免多執行緒同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢
。所以現在已經不太常用了。
2.1、Stack(類)
Stack是Vector提供的一個子類,用於模擬"棧"這種資料結構(LIFO後進先出)
3、LinkedList (類)
- LinkedList是用連結串列結構儲存資料的,很適合資料的動態插入和刪除,隨機訪問和遍歷速度比較慢。
- 另外,它還實現了Deque介面,專門用於操作表頭和表尾元素,可以當作堆疊、佇列和雙向佇列使用。
名稱 | 擴容方式(預設) | 執行緒安全 | 速度 | 有效個數的屬性 |
---|---|---|---|---|
ArrayList | 增長50% | 執行緒不安全 | 快 | size |
Vector | 增長一倍 | 執行緒安全 | 慢 | elementCount |
共同點 | 如果新增的有效元素個數超過陣列本身的長度,都會導致陣列進行擴容 | - | remove,add(index,obj)方法都會導致內部陣列進行資料拷貝的操作,這樣在大資料量時,可能會影響效率 | - |
其他
List介面的排序可以通過Collections.sort()來進行定製排序。
只需要繼承Comparable介面後,重寫compareTo()方法。
public class Student extends Thread implements Comparable {
private int age;
private String name;
private String tel;
private int height;
public Student( String name,int age, String tel, int height) {
this.age = age;
this.name = name;
this.tel = tel;
this.height = height;
}
public static void main(String args[]) throws InterruptedException{
Student stu1 = new Student("張三",21,"156482",172);
Student stu2 = new Student("李四",18,"561618",168);
Student stu3 = new Student("王五",19,"841681",170);
Student stu4 = new Student("趙七",20,"562595",180);
List<Student> list = new ArrayList<Student>();
//亂序插入
list.add(stu3);
list.add(stu1);
list.add(stu4);
list.add(stu2);
System.out.println("-----------排序前----------");
Iterator<Student> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
/*
* 使用Collections的sort方法讓集合排序,使用其方法必須要重寫
* Comparable介面的compareTo()方法
* */
Collections.sort(list);
System.out.println("-----------按照年齡排序後----------");
for(int i=0;i<list.size();i++){
System.out.println(list.get(i).toString());
}
}
//重寫compareTo方法,用age來比較。也可以用別的來比較
@Override
public int compareTo(Object o) {
//使用當前物件的年齡和其他物件的年齡比較,如果<0返回負數,>0返回正數,=0返回0
int z = this.age - ((Student)o).getAge();
if(z<0)
return -1; // 返回其他負數也行
else if(z == 0)
return 0;
else
return 1; //返回其他正數也行
}
//重寫toString,便於輸出
@Override
public String toString(){
return name+","+age+","+tel+","+height;
}
}
Set介面
- Set,顧名思義,集合的意思。java的集合和數學的集合一樣,滿足集合的無序性,確定性,單一性。同時,如果有多個null,則不滿足單一性了,所以Set只能有
一個null
。 - Set判斷兩個物件相同不是使用"=="運算子,而是根據equals方法。也就是說,我們在加入一個新元素的時候,如果這個新元素物件和Set中已有物件進行注意equals比較都返回false,則Set就會接受這個新元素物件,否則拒絕。
——因為Set的這個制約,在使用Set集合的時候,應該注意兩點:
1、為Set集合裡的元素的實現類實現一個有效的equals(Object)方法;
2、對Set的建構函式,傳入的Collection引數不能包含重複的元素。
Set的子類/子介面
- Set最流行的實現類有HashSet、TreeSet、LinkedHashSet(從HashSet繼承而來)。
1、 HashSet (類)
- HashSet是Set介面的典型實現,HashSet使用HASH演算法來儲存集合中的元素,因此具有良好的存取和查詢效能。當向HashSet集合中存入一個元素時,HashSet會呼叫該物件的 hashCode()方法來得到該物件的hashCode值,然後根據該HashCode值決定該物件在HashSet中的儲存位置。
- 值得主要的是,HashSet集合判斷兩個元素相等的標準是兩個物件通過equals()方法比較相等,並且兩個物件的hashCode()方法的返回值相等
1.1、LinkedHashSet(類)
- LinkedHashSet集合也是根據元素的hashCode值來決定元素的儲存位置,但和HashSet不同的是,它同時使用連結串列維護元素的次序,這樣使得元素看起來是以插入的順序儲存的。
- 當遍歷LinkedHashSet集合裡的元素時,LinkedHashSet將會按元素的新增順序來訪問集合裡的元素。
- LinkedHashSet需要維護元素的插入順序,因此效能略低於HashSet的效能,但在迭代訪問Set裡的全部元素時(遍歷)將有很好的效能(連結串列很適合進行遍歷)
2、SortedSet (介面)
- 此介面主要用於排序操作,實現了此介面的子類都屬於排序的子類
2.1、TreeSet(類)
- TreeSet是SortedSet介面的實現類,TreeSet可以確保集合元素處於排序狀態
3、EnumSet (類)
- EnumSet是一個專門為列舉類設計的集合類,EnumSet中所有元素都必須是指定列舉型別的列舉值,該列舉型別在建立EnumSet時顯式或隱式地指定。EnumSet的集合元素也是有序的,
Queue介面
- 此介面用於模擬“佇列”資料結構(FIFO)。新插入的元素放在隊尾,隊頭存放著儲存時間最長的元素。
Queue的子類/子介面
1、PriorityQueue—— 優先佇列(類)
- 其實它並沒有按照插入的順序來存放元素,而是按照佇列中某個屬性的大小來排列的。故而叫優先佇列。
2、Deque——雙端佇列(介面)
2.1、ArrayDeque(類)
- 基於陣列的雙端佇列,類似於ArrayList有一個Object[] 陣列。
2.2、LinkedList (類)(上文已有)
上述三個介面的區別:
容器名 | 是否有序 | 是否可重複 | null的個數 |
---|---|---|---|
List | 有序 | 可重複 | 允許多個null |
Set | 無序 | 不可重複 | 只允許一個null |
Queue | 有序(FIFO) | 可重複 | 通常不允許插入null |
Map 介面
-
Map
不是
collection的子介面或者實現類。Map是一個介面。 -
Map用於儲存具有“對映關係”的資料。每個Entry都持有鍵-值兩個物件。其中,Value可能重複,但是Key不允許重複(和Set類似)。
-
Map可以有多個Value為null,但是隻能有一個Key為null。
Map的子類/子介面
1、HashMap (類)
- 和HashSet集合不能保證元素的順序一樣,HashMap也不能保證key-value對的順序。並且類似於HashSet判斷兩個key是否相等的標準一樣: 兩個key通過equals()方法比較返回true、 同時兩個key的hashCode值也必須相等
1.1、LinkedHashMap (類)
- LinkedHashMap也使用雙向連結串列來維護key-value對的次序,該連結串列負責維護Map的迭代順序,與key-value對的插入順序一致(注意和TreeMap對所有的key-value進行排序區分)。
2、HashTable (類)
是一個古老的Map實現類。
2.1、Properties(類)
- Properties物件在處理屬性檔案時特別方便(windows平臺的.ini檔案)。Properties類可以把Map物件和屬性檔案關聯,從而把Map物件的key - value對寫入到屬性檔案中,也可把屬性檔案中的“屬性名-屬性值”載入進Map物件中。
3、SortedMap(介面)
如同Set->SortedSet->TreeSet一樣,Map也有Map->SortedMap->TreeMap的繼承關係。
3.1、TreeMap(類)
- TreeMap是一個紅黑樹結構,每個鍵值對都作為紅黑樹的一個節點。TreeMap儲存鍵值對時,需要根據key對節點進行排序,TreeMap可以保證所有的key-value對處於有序狀態。 同時,TreeMap也有兩種排序方式:自然排序、定製排序(類似於上面List的重寫CompareTo()方法)。
4、WeakHashMap(類)
- 看名字就能發現,這是Weak後的HashMap。但是二者大體差別不大。
- 區別在於,HashMap的key保留了對實際物件的
強引用
,這意味著只要該HashMap物件不被銷燬,該HashMap所引用的物件就不會被垃圾回收。 - 但WeakHashMap的key只保留了對實際物件的
弱引用
,這意味著如果WeakHashMap物件的key所引用的物件沒有被其他強引用變數所引用,則這些key所引用的物件可能被垃圾回收,當垃圾回收了該key所對應的實際物件之後,WeakHashMap也可能自動刪除這些key所對應的key-value對。
5、IdentityHashMap(類)
-
這個類也和HashMap類似,區別在於,在IdentityHashMap中,當且僅當兩個key嚴格相等(key1==key2)時,IdentityHashMap才認為兩個key相等
-
IdentityHashMap不是Map的通用實現,它有意違反了Map的常規協定。並且IdentityHashMap允許key和value都為null。
-
同HashMap,IdentityHashMap也是無序的,並且該類不是執行緒安全的,如果要使之執行緒安全,可以呼叫
Collections.synchronizedMap(new IdentityHashMap(…))
方法來實現。
6、EnumMap(類)
- EnumMap是一個與列舉類一起使用的Map實現,EnumMap中的所有key都必須是單個列舉類的列舉值。建立EnumMap時必須顯式或隱式指定它對應的列舉類。EnumMap根據key的自然順序儲存。