Java核心知識體系6:集合框架詳解

2023-11-13 15:00:33

Java核心知識體系1:泛型機制詳解
Java核心知識體系2:註解機制詳解
Java核心知識體系3:異常機制詳解
Java核心知識體系4:AOP原理和切面應用
Java核心知識體系5:反射機制詳解

1 集合框架圖總覽


我們來簡單解讀下上面這個框架圖:

  • 所有集合類都位於java.util包下
  • Iterator是遍歷集合的工具,我們經常通過Iterator迭代器來遍歷集合。我們說Collection依賴於Iterator,是因為Collection的實現類都要實現iterator()函數,返回一個Iterator物件。ListIterator主要作用就是遍歷List。
  • Java的集合類主要由兩個介面派生而出:Collection和Map,作為Java集合框架的根介面,這兩個介面包含了一些子介面和實現類。
  • 集合介面:即圖中的 LinkIterator、List、Set、Queue、SortedMap、SortedMap 6個介面(即短虛線框部分),表示不同集合型別,是集合框架的基礎。
  • 抽象類:即圖中的 AbstractCollection、AbstractList、AbstractSet、AbstractMap、AbstractSequentialList 5個抽象類(長虛線框部分),抽象類只是對集合介面的部分實現,有需要的話可以繼續擴充套件,完善自定義集合類。
  • 實現類:即圖片中LinkHashMap、TreeMap等8個實現類(實線框部分),主要是對介面的具體實現。
  • Collection 介面包含一組允許重複的物件
  • Set 介面繼承 Collection,但是集合內的元素不重複。Set的實現類有HastSet和TreeSet。HashSet依賴於HashMap,它實際上是通過HashMap實現的;TreeSet依賴於TreeMap,它實際上是通過TreeMap實現的。
  • List 介面繼承 Collection,集合內元素允許重複,但維護了元素的插入順序,所以是個有序佇列。每一個元素都有它的索引。第一個元素的索引值是0。List的實現類有LinkedList, ArrayList, Vector, Stack。
  • Map介面是鍵-值物件頂層介面,下面還包含了一些子介面和實現類。AbstractMap是個抽象類,它實現了Map介面中的大部分API。而HashMap,TreeMap,WeakHashMap都是繼承於AbstractMap。Hashtable雖然繼承於Dictionary,但它實現了Map介面。
  • Set、List和Map是集合的三大類:
    • List:有序集合,集合中元素可重複,存取元素可以根據元素索引存取。
    • Set:無序集合,集合中元素不可以重複,存取集合中的元素只能根據元素自身資訊來存取(因此元素不允許重複)。
    • Map:Key-value模式的鍵值對元素,存取時根據元素key來讀取對應的value。
  • Arrays和Collections是運算元組、集合的兩個工具類。

完成對上面框架的整體介紹之後,我們接著對每個類別進行詳細的分析。

2 Collection介面

Collection介面是處理物件集合的根介面,其中定義了很多對元素進行操作的方法。Collection介面有兩個主要的子介面List和Set,注意Map不是Collection的子介面,這個要牢記。
Collection介面中的方法如下:

其中,有幾個比較常用的方法,比如方法add()新增一個元素到集合中,addAll()將指定集合中的所有元素新增到集合中,contains()方法檢測集合中是否包含指定的元素,toArray()方法返回一個表示集合的陣列。

另外,Collection中有一個iterator()函數,它的作用是返回一個Iterator介面。通常,我們通過Iterator迭代器來遍歷集合。ListIterator是List介面所特有的,在List介面中,通過ListIterator()返回一個ListIterator物件。

Collection介面有兩個常用的子介面,下面會詳細介紹。

2.1 List介面

List集合代表一個有序集合,集合中每個元素都有其對應的順序索引。List集合允許使用重複元素,可以通過索引來存取指定位置的集合元素。

List介面繼承於Collection介面,它可以定義一個允許重複的有序集合。因為List中的元素是有序的,所以我們可以通過使用索引(元素在List中的位置,類似於陣列下標)來存取List中的元素,這類似於Java的陣列。

List介面為Collection直接介面。List所代表的是有序的Collection,即它用某種特定的插入順序來維護元素順序。使用者可以對列表中每個元素的插入位置進行精確地控制,同時可以根據元素的整數索引(在列表中的位置)存取元素,並搜尋列表中的元素。實現List介面的集合主要有:ArrayList、LinkedList、Vector、Stack。

2.1.1 ArrayList

ArrayList是一個動態陣列,也是我們最常用的集合。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了陣列的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢位時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。

size、isEmpty、get、set、iterator 和 listIterator 操作都以固定時間執行。add 操作以分攤的固定時間執行,也就是說,新增 n 個元素需要 O(n) 時間(由於要考慮到擴容,所以這不只是新增元素會帶來分攤固定時間開銷那樣簡單)。

ArrayList擅長於隨機存取。同時ArrayList是非同步的。

2.1.2 LinkedList

同樣實現List介面的LinkedList與ArrayList不同,ArrayList是一個動態陣列,而LinkedList是一個雙向連結串列。所以它除了有ArrayList的基本操作方法外還額外提供了get,remove,insert方法在LinkedList的首部或尾部。

由於實現的方式不同,LinkedList不能隨機存取,它所有的操作都是要按照雙重連結串列的需要執行。在列表中索引的操作將從開頭或結尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。

與ArrayList一樣,LinkedList也是非同步的。如果多個執行緒同時存取一個List,則必須自己實現存取同步。一種解決方法是在建立List時構造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(...));

2.1.3 Vector

與ArrayList相似,但是Vector是同步的。所以說Vector是執行緒安全的動態陣列。它的操作與ArrayList幾乎一樣。

2.1.4 Stack

Stack繼承自Vector,實現一個後進先出的堆疊。Stack提供5個額外的方法使得Vector得以被當作堆疊使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆疊是否為空,search方法檢測一個元素在堆疊中的位置。Stack剛建立後是空棧。

2.2 Set介面

Set是一種不包括重複元素的Collection。它維持它自己的內部排序,所以隨機存取沒有任何意義。與List一樣,它同樣允許null的存在但是僅有一個。由於Set介面的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變物件,如果在對集合中元素進行操作時,導致element1.equals(element2)為true,則必定會產生資料衝突的問題。Set介面有三個具體實現類,分別是

  • 雜湊集HashSet
  • 鏈式雜湊集LinkedHashSet
  • 樹形集TreeSet

Set是一種不包含重複的元素的Collection,無序,即任意的兩個元素element1和element2都有element1.equals(element2)為false,Set最多可以有一個null元素。需要注意的是,雖然Set中元素沒有順序性,但是元素在set中的位置是由該元素的HashCode決定的,所以具體的位置其實是固定的。

此外需要說明一點,在set介面中的不重複是有特殊要求的。
舉一個例子:物件A和物件B,本來是不同的兩個物件,正常情況下它們是能夠放入到Set裡面的,但是如果物件A和B的都重寫了hashcode和equals方法,並且重寫後的hashcode和equals方法是相同的話。那麼A和B是不能同時放入到Set集合中去的,也就是Set集合中的去重和hashcode與equals方法直接相關。

為了更好地理解,請看下面的例子:

 private static void setWork() {
        Set<String> set = new HashSet<>();
        set.add("Brand1");
        set.add("Brand2");
        set.add("Brand1");
        System.out.println("Set Size:" + set.size());
        System.out.println("Set Elements:" + set.toString());
		
		//再次新增一個字串物件 Brand2,然後通過equals方法比較,發現是相等的,所以新增失敗返回false
        boolean result = set.add(new String("Brand2"));
        System.out.println(result);
        System.out.println(set);
    }

執行結果:
Set Size:2
Set Elements:[Brand1, Brand2]
false
[Brand1, Brand2]
可以看出,因為有hashcode和equals方法,用來比較指向的字串物件所儲存的字串是否相等,所以第二個Brand1加進去是無效的。
程式通過new關鍵字來建立新的字串物件Brand2,使用==運運算元判斷返回false,使用equals方法比較返回true,所以同樣不能新增到Set集合中,最終還是兩個元素。

2.2.1 HashSet

HashSet 是一個沒有重複元素的集合。它是由HashMap實現的,不保證元素的順序(這裡所說的沒有順序是指:元素插入的順序與輸出的順序不一致),而且HashSet允許使用null 元素。HashSet是非同步的,如果多個執行緒同時存取一個雜湊set,而其中至少一個執行緒修改了該set,那麼它必須保持外部同步。 HashSet按Hash演演算法來儲存集合的元素,因此具有很好的存取和查詢效能。
HashSet的實現方式大致如下,通過一個HashMap儲存元素,元素是存放在HashMap的Key中,而Value統一使用一個Object物件。
HashSet使用和理解中容易出現的誤區:

  • HashSet中存放null值
    HashSet中是允許存入null值的,但是在HashSet中僅僅能夠存入一個null值。
  • HashSet中儲存元素的位置是固定的
    HashSet中儲存的元素的是無序的,這個沒什麼好說的,但是由於HashSet底層是基於Hash演演算法實現的,使用了hashcode,所以HashSet中相應的元素的位置是固定的。
  • 必須小心操作可變物件(Mutable Object)。
    如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。

2.2.2 LinkedHashSet

LinkedHashSet繼承自HashSet,其底層是基於LinkedHashMap來實現的,有序,非同步。LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的儲存位置,但是它同時使用連結串列維護元素的次序。這樣使得元素看起來像是以插入順序儲存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的新增順序存取集合的元素。

2.2.3 TreeSet

TreeSet是一個有序集合,其底層是基於TreeMap實現的,非執行緒安全。TreeSet可以確保集合元素處於排序狀態。TreeSet支援兩種排序方式,自然排序和客製化排序,其中自然排序為預設的排序方式。當我們構造TreeSet時,若使用不帶引數的建構函式,則TreeSet的使用自然比較器;若使用者需要使用自定義的比較器,則需要使用帶比較器的引數。
注意:TreeSet集合不是通過hashcode和equals函數來比較元素的.它是通過compare或者comparaeTo函數來判斷元素是否相等.compare函數通過判斷兩個物件的id,相同的id判斷為重複元素,不會被加入到集合中。

3 Map介面

Map與List、Set介面不同,它是由一系列鍵值對組成的集合,提供了key到Value的對映。同時它也沒有繼承Collection。在Map中它保證了key與value之間的一一對應關係。也就是說一個key對應一個value,所以它不能存在相同的key值,當然value值可以相同。

3.1 HashMap

以雜湊表資料結構實現,查詢物件時通過雜湊函數計算其位置,它是為快速查詢而設計的,其內部定義了一個hash表陣列(Entry[] table),元素會通過雜湊轉換函數將元素的雜湊地址轉換成陣列中存放的索引,如果有衝突,則使用雜湊連結串列的形式將所有相同雜湊地址的元素串起來,可能通過檢視HashMap.Entry的原始碼它是一個單連結串列結構。

3.2 LinkedHashMap

LinkedHashMap是HashMap的一個子類,它保留插入的順序,如果需要輸出的順序和輸入時的相同,那麼就選用LinkedHashMap。
LinkedHashMap是Map介面的雜湊表和連結列表實現,具有可預知的迭代順序。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。
LinkedHashMap實現與HashMap的不同之處在於,後者維護著一個執行於所有條目的雙重連結列表。此連結列表定義了迭代順序,該迭代順序可以是插入順序或者是存取順序。
根據連結串列中元素的順序可以分為:按插入順序的連結串列,和按存取順序(呼叫get方法)的連結串列。預設是按插入順序排序,如果指定按存取順序排序,那麼呼叫get方法後,會將這次存取的元素移至連結串列尾部,不斷存取可以形成按存取順序排序的連結串列。
注意,此實現不是同步的。如果多個執行緒同時存取連結的雜湊對映,而其中至少一個執行緒從結構上修改了該對映,則它必須保持外部同步。
由於LinkedHashMap需要維護元素的插入順序,因此效能略低於HashMap的效能,但在迭代存取Map裡的全部元素時將有很好的效能,因為它以連結串列來維護內部順序。

3.3 TreeMap

TreeMap 是一個有序的key-value集合,非同步,基於紅黑樹(Red-Black tree)實現,每一個key-value節點作為紅黑樹的一個節點。TreeMap儲存時會進行排序的,會根據key來對key-value鍵值對進行排序,其中排序方式也是分為兩種,一種是自然排序,一種是客製化排序,具體取決於使用的構造方法。
自然排序:TreeMap中所有的key必須實現Comparable介面,並且所有的key都應該是同一個類的物件,否則會報ClassCastException異常。
客製化排序:定義TreeMap時,建立一個comparator物件,該物件對所有的treeMap中所有的key值進行排序,採用客製化排序的時候不需要TreeMap中所有的key必須實現Comparable介面。
TreeMap判斷兩個元素相等的標準:兩個key通過compareTo()方法返回0,則認為這兩個key相等。
如果使用自定義的類來作為TreeMap中的key值,且想讓TreeMap能夠良好的工作,則必須重寫自定義類中的equals()方法,TreeMap中判斷相等的標準是:兩個key通過equals()方法返回為true,並且通過compareTo()方法比較應該返回為0。

4 Iterator 與 ListIterator詳解

4.1 Iterator

Iterator的定義如下:

public interface Iterator<E> {}

Java的Iterator(迭代器)是一個設計模式,它使你可以遍歷一個容器(如列表,集合,佇列等)。它提供了一種方法來順序存取聚合物件的元素,而不需要暴露該物件的內部表示。
Iterator提供的API介面如下:

  • boolean hasNext():判斷集合裡是否存在下一個元素。如果有,hasNext()方法返回 true。
  • Object next():返回集合裡下一個元素。
  • void remove():刪除集合裡上一次next方法返回的元素。
    參考如下:
import java.util.*;  
  
public class Main {  
  public static void main(String[] args) {  
     // 建立一個ArrayList物件
        List<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");
        list.add("Java");

        // 獲取該ArrayList的迭代器
        Iterator<String> it = list.iterator();

        // 使用迭代器遍歷列表中的元素
        while(it.hasNext()) {
            String element = it.next();
            System.out.println(element);
            if ("Java".equals(element)) {
                it.remove();
            }
        }
        // 移除之後的ArrayList物件
        System.out.println("after remove element 「java」: " + list);
  }  
}

輸出結果如下:

Hello
World
Java
remove java element : [Hello, World]

需要注意的點如下:

  • Iterator只能單向移動。
  • Iterator.remove()是唯一安全在迭代過程中修改集合;如果在迭代過程中以任何其它的方式修改了基本集合將會產生未知的行為。而且每呼叫一次next()方法,remove()方法只能被呼叫一次,如果違反這個規則將丟擲一個異常,因為可能導致資料異常。

4.2 ListIterator

ListIterator是一個功能更加強大的迭代器, 它繼承於Iterator介面,只能用於各種List型別的存取。它提供了在列表中插入和刪除元素的方法,以及使用hasPrevious()和previous()方法在迭代過程中向前和向後遍歷列表的功能。
以下是ListIterator的主要方法:

  • boolean hasNext(): 返回true如果迭代器有下一個元素。
  • Object next(): 返回迭代器的下一個元素並將指標移到下一個元素。
  • boolean hasPrevious(): 返回true如果迭代器有前一個元素。
  • Object previous(): 返回迭代器的前一個元素並將指標移到前一個元素。
  • int nextIndex(): 返回迭代器下一次要存取的元素的索引。
  • int previousIndex(): 返回迭代器上一次存取的元素的索引。
  • void remove(): 從列表中刪除迭代器最後一次返回的元素。
  • void add(Object o): 在迭代器指向的位置插入指定的元素。
  • void set(E e): 從列表中替換迭代器最後一次返回的元素。
public interface ListIterator<E> extends Iterator<E> {
    boolean hasNext(); 
    E next(); 
    boolean hasPrevious(); 
    E previous(); 
    int nextIndex(); 
    int previousIndex(); 
    void remove(); 
    void set(E e); 
    void add(E e);
}

由以上定義我們可以推出ListIterator可以:

  • 雙向移動(向前或者向後遍歷)
  • 產生相對於迭代器在列表中指向的當前位置的前一個和後一個元素的索引
  • 可以使用set()方法替換它存取過的最後一個元素
  • 可以使用add()方法在next()方法返回的元素之前或previous()方法返回的元素之後插入一個元素

使用範例:

    public static void listIteratorWork() {
        // 建立一個 ArrayList
        List<String> list = new ArrayList<>();
        list.add("Element A");
        list.add("Element B");
        list.add("Element C");

        System.out.println("當前列表 : " + list);

        // 獲取 ListIterator 物件
        ListIterator<String> listIterator = list.listIterator();
        // 使用 hasNext() 和 next() 方法迭代列表
        System.out.println("逐一遍歷 : ");
        while (listIterator.hasNext()) {
            System.out.println(listIterator.next() + ", " + listIterator.previousIndex() + ", " + listIterator.nextIndex());
        }

        // 在迭代過程中使用 add() 方法新增元素
        listIterator.add("Element D");
        System.out.println("新增一個元素之後:" + list);


        // 在迭代過程中使用 set() 方法進行元素修改
        listIterator = list.listIterator(1);
        System.out.print("修改一個元素之後:");
        while (listIterator.hasNext()) {
            if ("Element D".equals(listIterator.next())) {
                listIterator.set("Element replace");
            }           
        }
        System.out.println(list);        
    }

輸出結果如下:

當前列表 : [Element A, Element B, Element C]
逐一遍歷 : 
Element A, 0, 1
Element B, 1, 2
Element C, 2, 3
新增一個元素之後:[Element A, Element B, Element C, Element D]
修改一個元素之後:[Element A, Element B, Element C, Element replace]

5 面試考點分析

5.1 ArrayList和LinkedList對比

  • ArrayList是實現了基於動態陣列的資料結構,LinkedList基於連結串列的資料結構。
  • 兩者都是執行緒不安全,都實現了Collection介面。
  • 資料結構:ArrayList是基於動態陣列的資料結構,LinkedList是基於雙向連結串列的資料結構。
  • 效能:ArrayList支援隨機存取,查詢快,增刪慢,查詢的時間複雜度為O(1),插入和刪除的時間複雜度為O(n),因為對插入和刪除位置後面的元素進行移動位置,以保證記憶體的連續性,所以
    • 對於隨機存取get和set,ArrayList絕對優於LinkedList,因為LinkedList要移動指標。
    • 對於新增和刪除操作add和remove,LinedList比較佔優勢,因為ArrayList要行動資料。
  • 記憶體空間佔用: ArrayList的空 間浪費主要體現在在list列表的結尾會預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗 比ArrayList更多的空間(因為要存放直接後繼和直接前驅以及資料)。

5.2 HashTable與HashMap對比

  • 相同點:
    • 都實現了Map、Cloneable、java.io.Serializable介面。
    • 都是儲存"鍵值對(key-value)"的雜湊表,而且都是採用拉鍊法實現的。
  • 不同點:
    • 是否安全:HashMap是非執行緒安全的,HashTable 是執行緒安全的;HashTable 內部的方法基本都經過 synchronized 修飾。(如果你要保證執行緒安全的話就使用 ConcurrentHashMap )
    • 同步性:HashTable是執行緒安全的,也就是說是同步的,而HashMap是執行緒序不安全的,不是同步的 。
    • 對null值的處理:HashMap的key、value都可為null,HashTable的key、value都不可為null 。
    • 基礎類別不同:HashMap繼承於AbstractMap,而Hashtable繼承於Dictionary。
    • 支援的遍歷種類不同:HashMap只支援Iterator(迭代器)遍歷。而Hashtable支援Iterator(迭代器)和Enumeration(列舉元)兩種方式遍歷。
    • 操作效率:因為執行緒安全的問題,HashMap 要比 HashTable 效率高一點。另外,HashTable 基本被淘汰,不要在程式碼中使用它;
    • 對Null key 和Null value的支援: HashMap 中,null 可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為 null。但是在 HashTable 中 put 進的鍵值只要有一個 null,直接丟擲 NullPointerException
    • 初始容量大小和每次擴充容量大小的不同 :
      • 建立時如果不指定容量初始值,Hashtable 預設的初始大小為11,之後每次擴充,容量變為原來的2n+1。HashMap 預設的初始化大小為16。之後每次擴充,容量變為原來的2倍。
      • 建立時如果給定了容量初始值,那麼 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充為2的冪次方大小。也就是說 HashMap 總是使用2的冪作為雜湊表的大小,後面會介紹到為什麼是2的冪次方。
    • 底層資料結構: JDK1.8 以後的 HashMap 在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為8)時,將連結串列轉化為紅黑樹,以減少搜尋時間。Hashtable 沒有這樣的機制。

5.3 LinkedHashMap和TreeMap比較

LinkedHashMap儲存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時用帶引數,按照應用次數排序。在遍歷的時候會比HashMap慢。

TreeMap實現SortMap介面,內部實現是紅黑樹。能夠把它儲存的記錄根據鍵排序,預設是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時,得到的記錄是排過序的。TreeMap不允許key的值為null。非同步的。

5.4 HashSet、LinkedHashSet、TreeSet比較

5.4.1 Set介面

Set不允許包含相同的元素,如果試圖把兩個相同元素加入同一個集合中,add方法返回false。
Set判斷兩個物件相同不是使用==運運算元,而是根據equals方法。也就是說,只要兩個物件用equals方法比較返回true,Set就不會接受這兩個物件。

5.4.2 HashSet

HashSet有以下特點:

  • 不能保證元素的排列順序,順序有可能發生變化。
  • 不是同步的。
  • 集合元素可以是null,但只能放入一個null。
    HashSet集合判斷兩個元素相等的標準是兩個物件通過equals方法比較相等,並且兩個物件的hashCode()方法返回值也相等。

5.4.3 LinkedHashSet

LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的儲存位置,但是它同時使用連結串列維護元素的次序。這樣使得元素看起來像是以插入順序儲存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的新增順序存取集合的元素。
LinkedHashSet在迭代存取Set中的全部元素時,效能比HashSet好,但是插入時效能稍微遜色於HashSet。

5.4.4 TreeSet類

TreeSet是SortedSet介面的唯一實現類,TreeSet可以確保集合元素處於排序狀態。TreeSet支援兩種排序方式,自然排序和客製化排序,其中自然排序為預設的排序方式。向TreeSet中加入的應該是同一個類的物件。
TreeSet判斷兩個物件不相等的方式是兩個物件通過equals方法返回false,或者通過CompareTo方法比較沒有返回0。

5.5 Iterator和ListIterator區別

  • ListIterator有add()方法,可以向List中新增物件,而Iterator不能
  • ListIterator和Iterator都有hasNext()和next()方法,可以實現順序向後遍歷,但是ListIterator有hasPrevious()和previous()方法,可以實現逆向(順序向前)遍歷。Iterator就不可以。
  • ListIterator可以定位當前的索引位置,nextIndex()和previousIndex()可以實現。Iterator沒有此功能。
  • 都可實現刪除物件,但是ListIterator可以實現物件的修改,set()方法可以實現。Iierator僅能遍歷,不能修改。
    因為ListIterator的這些功能,可以方便的實現對LinkedList等List資料結構的操作。其實,陣列物件也可以用迭代器來實現。

5.6 Collection 和 Collections區別

Java中的Collection和Collections都是用於處理集合的類,但它們有一些重要的區別。

繼承關係:Collection是所有集合類的根介面,它定義了集合的基本操作,比如新增元素、刪除元素等。Collections是一個幫助類,它提供了靜態方法來操作和操作集合,比如排序、查詢等。Collections類通過實現和範例化集合類的各種基本操作,讓集合類的操作更加簡單。
用法:Collection通常用於定義集合類的基本操作,而Collections則提供了各種靜態方法來操作和操作集合。Collections類中包含了很多有用的靜態方法,比如排序、查詢、複製等。