Java 集合(1)之 總體架構

TimberLiu發表於2019-02-20

集合框架

Java 提供了一個豐富的集合類,包含了常用的資料結構和演算法等。使用 Java 集合的優點部分如下:

  • 降低開發的成本:通過提供的核心集合類,使程式設計師更專注地實現程式的核心功能,而不用自己去實現自己的集合類;
  • 提高程式碼的質量:集合框架提供了許多經過嚴格測試的、高效能、高質量的資料結構和演算法,大大提高了程式的質量;
  • 促進軟體的複用性:只要符合標準集合介面的新資料結構和演算法本質上都是可以複用的。

在集合的介面和實現中大量使用了泛型,它為集合提供了一個可以容納的物件型別,如果新增其他型別的元素,在編譯時就會出錯,這避免了在執行時出現型別轉換異常。泛型也使得程式碼更加整潔,因為不需要顯式地編寫型別轉換操作,編譯器會幫我們實現。

Java 整個集合框架圖如下:

Java 集合(1)之 總體架構

可以看到,這個框圖主要有兩個主幹:CollectionMap

  • Collection:它是一個介面,提供了對集合物件進行基本操作的通用介面方法,有很多具體的實現和繼承,它被分為三大分支:ListSetQueue
  • Map:它是由一系列鍵值對組成的集合,提供了 keyValue 的對映。

除此之外,還有 Iterator 迭代器,CollectionsArrays 工具類,Comparator 比較器等。

List

List 是一個有序列表,用特定的插入順序來維護元素順序。可以對列表中元素的插入位置進行控制,同時可以根據元素的索引訪問元素。實現 List 介面的主要有 ArrayListLinkedListVector 等。

ArrayList

ArrayList 是一個動態陣列,在隨機訪問元素時效能較高,但插入和刪除元素效率較低。ArrayList 都有一個初始容量,代表了陣列的大小,在 ArrayList 快滿時,會進行擴容操作,每次增長 1.5 倍大小。但 ArrayList 是非同步的,在多執行緒場景下不要使用。

LinkedList

LinkedList 是一個雙向連結串列,由於實現方式不同,它不支援隨機訪問,但很容易在列表中間進行插入和刪除操作。與 ArrayList 一樣,LinkedList 也是非同步的。

Vector

VectorArrayList 類似,基於動態陣列實現,但 Vector 是同步的。它的操作與 ArrayList 幾乎一樣。

Map

Map 是由一系列鍵值對組成的集合,提供了 keyValue 的對映。實現 Map 介面的有:HashMapTreeMapHashTableEnumMap 等。

HashMap

HashMap 以雜湊表資料結構實現,查詢物件時通過雜湊函式將元素的雜湊地址轉換成陣列索引,在出現碰撞衝突時,則使用連結串列的形式儲存雜湊地址相同的元素,在 JDK8 後,連結串列過長後會轉換為紅黑樹。HashMap 儲存和查詢效率較高,但需要考慮雜湊函式、碰撞衝突等問題。

TreeMap

TreeMap 實現了 SortedMap 介面,內部以紅黑樹資料結構實現,其中鍵以某種排序規則排序,排序規則也可以通過 Comparator 比較器指定。

HashTable

HashTable 也是以雜湊表資料結構實現,遇到衝突時採用連結串列的形式。類似於 HashMap,但它的同步的。

EnumMap

EnumMap 是將列舉型別作為鍵值的 Map。由於鍵的數量相對固定,所以在內部用一個陣列儲存對應值。通常來說,效率高於 HashMap

Set

Set 是一個不包括重複元素的集合,存入的元素沒有順序。內部通過 Map 實現,Set 裡儲存的值對應的是 Map 中的鍵,鍵對應的值是不變的,指向一個常量。實現 Set 介面的集合有:HashSetTreeSetEnumSet 等。

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

ComparatorComparable 是兩個介面,都可以用來對物件進行比較。

  • Comparable 介面用於當前物件和其他物件進行比較。它有一個 compareTo 方法,該方法只有一個引數。返回值為 int,大於 0 表示當前物件大於引數物件;小於 0 表示當前物件小於引數物件;等於 0 表示兩者相等。
  • Comparator 是一個比較器介面,用於對傳入的兩個物件進行比較。它有一個 compare 方法,該方法有兩個引數。

例如,對一組 Student 物件進行排序,分別使用 ComparableComparator 介面實現功能。

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);
    }
}
複製程式碼

相關文章