集合框架
Java
提供了一個豐富的集合類,包含了常用的資料結構和演算法等。使用 Java
集合的優點部分如下:
- 降低開發的成本:通過提供的核心集合類,使程式設計師更專注地實現程式的核心功能,而不用自己去實現自己的集合類;
- 提高程式碼的質量:集合框架提供了許多經過嚴格測試的、高效能、高質量的資料結構和演算法,大大提高了程式的質量;
- 促進軟體的複用性:只要符合標準集合介面的新資料結構和演算法本質上都是可以複用的。
在集合的介面和實現中大量使用了泛型,它為集合提供了一個可以容納的物件型別,如果新增其他型別的元素,在編譯時就會出錯,這避免了在執行時出現型別轉換異常。泛型也使得程式碼更加整潔,因為不需要顯式地編寫型別轉換操作,編譯器會幫我們實現。
Java
整個集合框架圖如下:
可以看到,這個框圖主要有兩個主幹:Collection
和 Map
。
Collection
:它是一個介面,提供了對集合物件進行基本操作的通用介面方法,有很多具體的實現和繼承,它被分為三大分支:List
、Set
和Queue
。Map
:它是由一系列鍵值對組成的集合,提供了key
到Value
的對映。
除此之外,還有 Iterator
迭代器,Collections
和 Arrays
工具類,Comparator
比較器等。
List
List
是一個有序列表,用特定的插入順序來維護元素順序。可以對列表中元素的插入位置進行控制,同時可以根據元素的索引訪問元素。實現 List
介面的主要有 ArrayList
、LinkedList
、Vector
等。
ArrayList
ArrayList
是一個動態陣列,在隨機訪問元素時效能較高,但插入和刪除元素效率較低。ArrayList
都有一個初始容量,代表了陣列的大小,在 ArrayList
快滿時,會進行擴容操作,每次增長 1.5
倍大小。但 ArrayList
是非同步的,在多執行緒場景下不要使用。
LinkedList
LinkedList
是一個雙向連結串列,由於實現方式不同,它不支援隨機訪問,但很容易在列表中間進行插入和刪除操作。與 ArrayList
一樣,LinkedList
也是非同步的。
Vector
Vector
與 ArrayList
類似,基於動態陣列實現,但 Vector
是同步的。它的操作與 ArrayList
幾乎一樣。
Map
Map
是由一系列鍵值對組成的集合,提供了 key
到 Value
的對映。實現 Map
介面的有:HashMap
、TreeMap
、HashTable
、EnumMap
等。
HashMap
HashMap
以雜湊表資料結構實現,查詢物件時通過雜湊函式將元素的雜湊地址轉換成陣列索引,在出現碰撞衝突時,則使用連結串列的形式儲存雜湊地址相同的元素,在 JDK8
後,連結串列過長後會轉換為紅黑樹。HashMap
儲存和查詢效率較高,但需要考慮雜湊函式、碰撞衝突等問題。
TreeMap
TreeMap
實現了 SortedMap
介面,內部以紅黑樹資料結構實現,其中鍵以某種排序規則排序,排序規則也可以通過 Comparator
比較器指定。
HashTable
HashTable
也是以雜湊表資料結構實現,遇到衝突時採用連結串列的形式。類似於 HashMap
,但它的同步的。
EnumMap
EnumMap
是將列舉型別作為鍵值的 Map
。由於鍵的數量相對固定,所以在內部用一個陣列儲存對應值。通常來說,效率高於 HashMap
。
Set
Set
是一個不包括重複元素的集合,存入的元素沒有順序。內部通過 Map
實現,Set
裡儲存的值對應的是 Map
中的鍵,鍵對應的值是不變的,指向一個常量。實現 Set
介面的集合有:HashSet
、TreeSet
、EnumSet
等。
HashSet
HashSet
底層基於 HashMap
實現,它內部元素的順序是由雜湊碼來決定的,所以它不保證 Set
的迭代順序。可以放入 null
,但只能放入一個。
TreeSet
與 HashSet
類似,它是基於 TreeMap
實現,以某種排序規則排序。它是使用元素的自然順序排序,或根據建立 Set
時提供的 Comparator
進行排序。但不允許存入 null
值。
EnumSet
EnumSet
基於 EnumMap
實現,是列舉專用的 Set
,其中所有元素都是列舉型別。
Queue
Queue
通常是指先進先出的佇列,也不允許隨機訪問佇列中的元素。而 Deque
介面是 Queue
的子介面,它代表一個雙端佇列。
ArrayDeque
ArrayDeque
是基於有首尾指標的陣列(環形緩衝區)實現的雙端佇列,它只能從首尾取出或插入元素。底層由陣列實現,可以指定容量,預設容量為 16
,並根據新增元素個數,動態擴充套件。
PriorityQueue
PriorityQueue
是一個優先順序佇列,它使用自然順序或者制定的比較器來排序。佇列的頭是按指定排序方式的最小元素。
Comparator 和 Comparable
Comparator
和 Comparable
是兩個介面,都可以用來對物件進行比較。
Comparable
介面用於當前物件和其他物件進行比較。它有一個compareTo
方法,該方法只有一個引數。返回值為int
,大於0
表示當前物件大於引數物件;小於0
表示當前物件小於引數物件;等於0
表示兩者相等。Comparator
是一個比較器介面,用於對傳入的兩個物件進行比較。它有一個compare
方法,該方法有兩個引數。
例如,對一組 Student
物件進行排序,分別使用 Comparable
和 Comparator
介面實現功能。
Comparable
Comparable
介面實現在物件類的內部,之後物件就變成了一個可以比較大小的物件,也就可以用來排序了。
首先 Student
類需要實現 Comparable
介面,重寫其 compareTo
方法:
public class Student implements Comparable<Student> {
private String name;
private int age;
// setter、getter、toString
@Override
public int compareTo(Student another) {
int flag = this.name.compareTo(another.name);
if(flag == 0) {
flag = this.age - another.age;
}
return flag;
}
}
複製程式碼
然後利用 List
介面的 sort(Comparator<? super E> c)
預設方法,或者 Collections
工具類的 sort(List<T> list)
方法進行排序:
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("a", 4));
students.add(new Student("d", 2));
students.add(new Student("c", 5));
students.add(new Student("c", 3));
students.sort(null);
// Collections.sort(students);
for (Student student : students) {
System.out.println(student);
}
}
複製程式碼
Comparator
Comparator
實現在物件類的外部,此時物件類的結構不需要有任何變化。
然後另外定義一個比較器類,實現 Comparator
介面並重寫其 compare
方法:
class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
int flag = o1.getName().compareTo(o2.getName());
if(flag == 0) {
flag = o1.getAge() - o2.getAge();
}
return flag;
}
}
複製程式碼
然後利用 List
介面的 sort(Comparator<? super E> c)
方法,或者 Collections
工具類的 sort(List<T> list, Comparator<? super T> c)
方法進行排序:
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("a", 4));
persons.add(new Person("d", 2));
persons.add(new Person("c", 5));
persons.add(new Person("c", 3));
persons.sort(new PersonComparator());
// Collections.sort(persons, new PersonComparator());
for (Person person : persons) {
System.out.println(person);
}
}
複製程式碼