Java 容器系列總結

暮夏有五發表於2021-02-04

為什麼要使用集合


當我們需要儲存一組型別相同的資料的時候,我們應該是用一個容器來儲存,這個容器就是陣列,但是,使用陣列儲存物件具有一定的弊端, 因為我們在實際開發中,儲存的資料的型別是多種多樣的,於是,就出現了“集合”,集合同樣也是用來儲存多個資料的。

陣列的缺點是一旦宣告之後,長度就不可變了;同時,宣告陣列時的資料型別也決定了該陣列儲存的資料的型別;而且,陣列儲存的資料是有序的、可重複的,特點單一。 但是集合提高了資料儲存的靈活性,Java 集合不僅可以用來儲存不同型別不同數量的物件,還可以儲存具有對映關係的資料。

Java 容器概述


從下圖可以看出,在 Java 中除了以 Map 結尾的類之外, 其他類都實現了 Collection 介面。

並且,以 Map 結尾的類都實現了 Map 介面。

img

如何選用集合


主要根據集合的特點來選用,比如我們需要根據鍵值獲取到元素值時就選用 Map 介面下的集合,需要排序時選擇 TreeMap,不需要排序時就選擇 HashMap,需要保證執行緒安全就選用 ConcurrentHashMap

當我們只需要存放元素值時,就選擇實現Collection 介面的集合,需要保證元素唯一時選擇實現 Set 介面的集合比如 TreeSetHashSet,不需要就選擇實現 List 介面的比如 ArrayListLinkedList,然後再根據實現這些介面的集合的特點來選用。

List、Set、Map 三者的區別


  • List(對付順序的好幫手): 儲存的元素是有序的、可重複的。
  • Set(注重獨一無二的性質): 儲存的元素是無序的、不可重複的。
  • Map(用 Key 來搜尋的專家): 使用鍵值對(kye-value)儲存,類似於數學上的函式 y=f(x),“x”代表 key,"y"代表 value,Key 是無序的、不可重複的,value 是無序的、可重複的,每個鍵最多對映到一個值。

底層資料結構

先來看一下 Collection 介面下面的集合。

1. List

  • ArraylistObject[]陣列
  • VectorObject[]陣列
  • LinkedList: 雙向連結串列(JDK1.6 之前為迴圈連結串列,JDK1.7 取消了迴圈)

2. Set

  • HashSet(無序,唯一): 基於 HashMap 實現的,底層採用 HashMap 來儲存元素
  • LinkedHashSetLinkedHashSetHashSet 的子類,並且其內部是通過 LinkedHashMap 來實現的。有點類似於我們之前說的 LinkedHashMap 其內部是基於 HashMap 實現一樣,不過還是有一點點區別的
  • TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹)

3. Map

再來看看 Map 介面下面的集合。

  • HashMap: JDK1.8 之前 HashMap 由陣列+連結串列組成的,陣列是 HashMap 的主體,連結串列則是主要為了解決雜湊衝突而存在的(“拉鍊法”解決衝突)。JDK1.8 以後在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為 8)(將連結串列轉換成紅黑樹前會判斷,如果當前陣列的長度小於 64,那麼會選擇先進行陣列擴容,而不是轉換為紅黑樹)時,將連結串列轉化為紅黑樹,以減少搜尋時間
  • LinkedHashMapLinkedHashMap 繼承自 HashMap,所以它的底層仍然是基於拉鍊式雜湊結構即由陣列和連結串列或紅黑樹組成。另外,LinkedHashMap 在上面結構的基礎上,增加了一條雙向連結串列,使得上面的結構可以保持鍵值對的插入順序。同時通過對連結串列進行相應的操作,實現了訪問順序相關邏輯。詳細可以檢視:《LinkedHashMap 原始碼詳細分析(JDK1.8)》
  • Hashtable: 陣列+連結串列組成的,陣列是 HashMap 的主體,連結串列則是主要為了解決雜湊衝突而存在的
  • TreeMap: 紅黑樹(自平衡的排序二叉樹)

Collection 子介面之 List


Arraylist 和 Vector 的區別

  • ArrayListList 的主要實現類,底層使用 Object[ ]儲存,適用於頻繁的查詢工作,執行緒不安全 ;
  • VectorList 的古老實現類,底層使用 Object[ ] 儲存,執行緒安全的。

Arraylist 與 LinkedList 區別

  1. 是否保證執行緒安全: ArrayListLinkedList 都是不同步的,也就是不保證執行緒安全;
  2. 底層資料結構: Arraylist 底層使用的是 Object 陣列LinkedList 底層使用的是 雙向連結串列 資料結構(JDK1.6 之前為迴圈連結串列,JDK1.7 取消了迴圈。注意雙向連結串列和雙向迴圈連結串列的區別,下面有介紹到!)
  3. 插入和刪除是否受元素位置的影響: ① ArrayList 採用陣列儲存,所以插入和刪除元素的時間複雜度受元素位置的影響。 比如:執行add(E e)方法的時候, ArrayList 會預設在將指定的元素追加到此列表的末尾,這種情況時間複雜度就是 O(1)。但是如果要在指定位置 i 插入和刪除元素的話(add(int index, E element))時間複雜度就為 O(n-i)。因為在進行上述操作的時候集合中第 i 和第 i 個元素之後的(n-i)個元素都要執行向後位/向前移一位的操作。 ② LinkedList 採用連結串列儲存,所以對於add(E e)方法的插入,刪除元素時間複雜度不受元素位置的影響,近似 O(1),如果是要在指定位置i插入和刪除元素的話((add(int index, E element)) 時間複雜度近似為o(n))因為需要先移動到指定位置再插入。
  4. 是否支援快速隨機訪問: LinkedList 不支援高效的隨機元素訪問,而 ArrayList 支援。快速隨機訪問就是通過元素的序號快速獲取元素物件(對應於get(int index)方法)。
  5. 記憶體空間佔用: ArrayList 的空 間浪費主要體現在在 list 列表的結尾會預留一定的容量空間,而 LinkedList 的空間花費則體現在它的每一個元素都需要消耗比 ArrayList 更多的空間(因為要存放直接後繼和直接前驅以及資料)。

雙向連結串列和雙向迴圈連結串列

雙向連結串列: 包含兩個指標,一個 prev 指向前一個節點,一個 next 指向後一個節點。

img

雙向迴圈連結串列: 最後一個節點的 next 指向 head,而 head 的 prev 指向最後一個節點,構成一個環。

img

Collection 子介面之 Set


comparable 和 Comparator 的區別

  • comparable 介面實際上是出自java.lang包 它有一個 compareTo(Object obj)方法用來排序
  • comparator介面實際上是出自 java.util 包它有一個compare(Object obj1, Object obj2)方法用來排序

一般我們需要對一個集合使用自定義排序時,我們就要重寫compareTo()方法或compare()方法,當我們需要對某一個集合實現兩種排序方式,比如一個 song 物件中的歌名和歌手名分別採用一種排序方法的話,我們可以重寫compareTo()方法和使用自制的Comparator方法或者以兩個 Comparator 來實現歌名排序和歌星名排序,第二種代表我們只能使用兩個引數版的 Collections.sort().

Comparator 定製排序

ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(-1);
arrayList.add(3);
arrayList.add(3);
arrayList.add(-5);
arrayList.add(7);
arrayList.add(4);
arrayList.add(-9);
arrayList.add(-7);
System.out.println("原始陣列:");
System.out.println(arrayList);
// void reverse(List list):反轉
Collections.reverse(arrayList);
System.out.println("Collections.reverse(arrayList):");
System.out.println(arrayList);

// void sort(List list),按自然排序的升序排序
Collections.sort(arrayList);
System.out.println("Collections.sort(arrayList):");
System.out.println(arrayList);
// 定製排序的用法
Collections.sort(arrayList, new Comparator<Integer>() {

    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
});
System.out.println("定製排序後:");
System.out.println(arrayList);Copy to clipboardErrorCopied

輸入如下:

原始陣列:
[-1, 3, 3, -5, 7, 4, -9, -7]
Collections.reverse(arrayList):
[-7, -9, 4, 7, -5, 3, 3, -1]
Collections.sort(arrayList):
[-9, -7, -5, -1, 3, 3, 4, 7]
定製排序後:
[7, 4, 3, 3, -1, -5, -7, -9]Copy to clipboardErrorCopied

無序性和不可重複性的含義

什麼是無序性:無序性不等於隨機性 ,無序性是指儲存的資料在底層陣列中並非按照陣列索引的順序新增 ,而是根據資料的雜湊值決定的。

什麼是不可重複性:不可重複性是指新增的元素按照 equals()判斷時 ,返回 false,需要同時重寫 equals()方法和 HashCode()方法。

HashSet、LinkedHashSet、TreeSet 的區別

  • HashSetSet 介面的主要實現類 ,HashSet 的底層是 HashMap,執行緒不安全的,可以儲存 null 值;

  • LinkedHashSetHashSet 的子類,能夠按照新增的順序遍歷;

  • TreeSet 底層使用紅黑樹,能夠按照新增元素的順序進行遍歷,排序的方式有自然排序和定製排序。

Map 介面


HashMap 和 Hashtable 的區別

  1. 執行緒是否安全: HashMap 是非執行緒安全的,HashTable 是執行緒安全的,因為 HashTable 內部的方法基本都經過synchronized 修飾。(如果你要保證執行緒安全的話就使用 ConcurrentHashMap 吧!);
  2. 效率: 因為執行緒安全的問題,HashMap 要比 HashTable 效率高一點。另外,HashTable 基本被淘汰,不要在程式碼中使用它;
  3. 對 Null key 和 Null value 的支援: HashMap 可以儲存 null 的 key 和 value,但 null 作為鍵只能有一個,null 作為值可以有多個;HashTable 不允許有 null 鍵和 null 值,否則會丟擲 NullPointerException
  4. 初始容量大小和每次擴充容量大小的不同 : ① 建立時如果不指定容量初始值,Hashtable 預設的初始大小為 11,之後每次擴充,容量變為原來的 2n+1。HashMap 預設的初始化大小為 16。之後每次擴充,容量變為原來的 2 倍。② 建立時如果給定了容量初始值,那麼 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充為 2 的冪次方大小(HashMap 中的tableSizeFor()方法保證,下面給出了原始碼)。也就是說 HashMap 總是使用 2 的冪作為雜湊表的大小,後面會介紹到為什麼是 2 的冪次方。
  5. 底層資料結構: JDK1.8 以後的 HashMap 在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為 8)(將連結串列轉換成紅黑樹前會判斷,如果當前陣列的長度小於 64,那麼會選擇先進行陣列擴容,而不是轉換為紅黑樹)時,將連結串列轉化為紅黑樹,以減少搜尋時間。Hashtable 沒有這樣的機制。

HashMap 中帶有初始容量的建構函式:

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
     public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }Copy to clipboardErrorCopied

下面這個方法保證了 HashMap 總是使用 2 的冪作為雜湊表的大小。

    /**
     * Returns a power of two size for the given target capacity.
     */
    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }Copy to clipboardErrorCopied

HashMap 和 HashSet 區別

如果你看過 HashSet 原始碼的話就應該知道:HashSet 底層就是基於 HashMap 實現的。(HashSet 的原始碼非常非常少,因為除了 clone()writeObject()readObject()HashSet 自己不得不實現之外,其他方法都是直接呼叫 HashMap 中的方法。

HashMap HashSet
實現了 Map 介面 實現 Set 介面
儲存鍵值對 僅儲存物件
呼叫 put()向 map 中新增元素 呼叫 add()方法向 Set 中新增元素
HashMap 使用鍵(Key)計算 hashcode HashSet 使用成員物件來計算 hashcode 值,對於兩個物件來說 hashcode 可能相同,所以 equals()方法用來判斷物件的相等性

HashMap 和 TreeMap 區別

TreeMapHashMap 都繼承自AbstractMap ,但是需要注意的是TreeMap它還實現了NavigableMap介面和SortedMap 介面。

img

實現 NavigableMap 介面讓 TreeMap 有了對集合內元素的搜尋的能力。

實現SortMap介面讓 TreeMap 有了對集合中的元素根據鍵排序的能力。預設是按 key 的升序排序,不過我們也可以指定排序的比較器。示例程式碼如下:

/**
 * @author shuang.kou
 * @createTime 2020年06月15日 17:02:00
 */
public class Person {
    private Integer age;

    public Person(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }


    public static void main(String[] args) {
        TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
            @Override
            public int compare(Person person1, Person person2) {
                int num = person1.getAge() - person2.getAge();
                return Integer.compare(num, 0);
            }
        });
        treeMap.put(new Person(3), "person1");
        treeMap.put(new Person(18), "person2");
        treeMap.put(new Person(35), "person3");
        treeMap.put(new Person(16), "person4");
        treeMap.entrySet().stream().forEach(personStringEntry -> {
            System.out.println(personStringEntry.getValue());
        });
    }
}Copy to clipboardErrorCopied

輸入如下:

person1
person4
person2
person3Copy to clipboardErrorCopied

可以看出,TreeMap 中的元素已經是按照 Person 的 age 欄位的升序來排列了。

上面,我們是通過傳入匿名內部類的方式實現的,你可以將程式碼替換成 Lambda 表示式實現的方式:

TreeMap<Person, String> treeMap = new TreeMap<>((person1, person2) -> {
  int num = person1.getAge() - person2.getAge();
  return Integer.compare(num, 0);
});Copy to clipboardErrorCopied

綜上,相比於HashMap來說 TreeMap 主要多了對集合中的元素根據鍵排序的能力以及對集合內元素的搜尋的能力。

HashSet 如何檢查重複

當你把物件加入HashSet時,HashSet 會先計算物件的hashcode值來判斷物件加入的位置,同時也會與其他加入的物件的 hashcode 值作比較,如果沒有相符的 hashcodeHashSet 會假設物件沒有重複出現。但是如果發現有相同 hashcode 值的物件,這時會呼叫equals()方法來檢查 hashcode 相等的物件是否真的相同。如果兩者相同,HashSet 就不會讓加入操作成功。

hashCode()equals() 的相關規定:

  1. 如果兩個物件相等,則 hashcode 一定也是相同的
  2. 兩個物件相等,對兩個 equals() 方法返回 true
  3. 兩個物件有相同的 hashcode 值,它們也不一定是相等的
  4. 綜上,equals() 方法被覆蓋過,則 hashCode() 方法也必須被覆蓋
  5. hashCode() 的預設行為是對堆上的物件產生獨特值。如果沒有重寫 hashCode(),則該 class 的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料)。

== 與 equals 的區別:

對於基本型別來說,== 比較的是值是否相等;

對於引用型別來說,== 比較的是兩個引用是否指向同一個物件地址(兩者在記憶體中存放的地址(堆記憶體地址)是否指向同一個地方);

對於引用型別(包括包裝型別)來說,equals 如果沒有被重寫,對比它們的地址是否相等;如果 equals()方法被重寫(例如 String),則比較的是地址裡的內容。

HashMap 的底層實現

JDK1.8 之前 HashMap 底層是 陣列和連結串列 結合在一起使用也就是 連結串列雜湊HashMap 通過 key 的 hashCode 經過擾動函式處理過後得到 hash 值,然後通過 (n - 1) & hash 判斷當前元素存放的位置(這裡的 n 指的是陣列的長度),如果當前位置存在元素的話,就判斷該元素與要存入的元素的 hash 值以及 key 是否相同,如果相同的話,直接覆蓋,不相同就通過拉鍊法解決衝突。

所謂擾動函式指的就是 HashMap 的 hash 方法。使用 hash 方法也就是擾動函式是為了防止一些實現比較差的 hashCode() 方法 換句話說使用擾動函式之後可以減少碰撞。

JDK 1.8 的 hash 方法 相比於 JDK 1.7 hash 方法更加簡化,但是原理不變。

    static final int hash(Object key) {
      int h;
      // key.hashCode():返回雜湊值也就是hashcode
      // ^ :按位異或
      // >>>:無符號右移,忽略符號位,空位都以0補齊
      return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  }Copy to clipboardErrorCopied

對比一下 JDK1.7 的 HashMap 中的 hash 方法原始碼.

static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).

    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}Copy to clipboardErrorCopied

相比於 JDK1.8 的 hash 方法 ,JDK 1.7 的 hash 方法的效能會稍差一點點,因為畢竟擾動了 4 次。

所謂 “拉鍊法” 就是:將連結串列和陣列相結合。也就是說建立一個連結串列陣列,陣列中每一格就是一個連結串列。若遇到雜湊衝突,則將衝突的值加到連結串列中即可。

相比於 JDK1.7 版本, JDK1.8 之後在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為 8)(將連結串列轉換成紅黑樹前會判斷,如果當前陣列的長度小於 64,那麼會選擇先進行陣列擴容,而不是轉換為紅黑樹)時,將連結串列轉化為紅黑樹,以減少搜尋時間。

img

TreeMap、TreeSet 以及 JDK1.8 之後的 HashMap 底層都用到了紅黑樹。紅黑樹就是為了解決二叉查詢樹的缺陷,因為二叉查詢樹在某些情況下會退化成一個線性結構。

HashMap 的長度為什麼是 2 的冪次方

為了能讓 HashMap 存取高效,儘量較少碰撞,也就是要儘量把資料分配均勻。我們上面也講到了過了,Hash 值的範圍值-2147483648 到 2147483647,前後加起來大概 40 億的對映空間,只要雜湊函式對映得比較均勻鬆散,一般應用是很難出現碰撞的。但問題是一個 40 億長度的陣列,記憶體是放不下的。所以這個雜湊值是不能直接拿來用的。用之前還要先做對陣列的長度取模運算,得到的餘數才能用來要存放的位置也就是對應的陣列下標。這個陣列下標的計算方法是“ (n - 1) & hash”。(n 代表陣列長度)。這也就解釋了 HashMap 的長度為什麼是 2 的冪次方。

這個演算法應該如何設計呢?

我們首先可能會想到採用%取餘的操作來實現。但是,重點來了:“取餘(%)操作中如果除數是 2 的冪次則等價於與其除數減一的與(&)操作(也就是說 hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方;)。” 並且 採用二進位制位操作 &,相對於%能夠提高運算效率,這就解釋了 HashMap 的長度為什麼是 2 的冪次方。

HashMap 多執行緒操作導致死迴圈問題

主要原因在於併發下的 Rehash 會造成元素之間會形成一個迴圈連結串列。不過,jdk 1.8 後解決了這個問題,但是還是不建議在多執行緒下使用 HashMap,因為多執行緒下使用 HashMap 還是會存在其他問題比如資料丟失。併發環境下推薦使用 ConcurrentHashMap 。

HashMap 常見的遍歷方式

HashMap 的 7 種遍歷方式與效能分析!

ConcurrentHashMap 和 Hashtable 的區別

ConcurrentHashMapHashtable 的區別主要體現在實現執行緒安全的方式上不同。

  • 底層資料結構: JDK1.7 的 ConcurrentHashMap 底層採用 分段的陣列+連結串列 實現,JDK1.8 採用的資料結構跟 HashMap1.8 的結構一樣,陣列+連結串列/紅黑二叉樹。Hashtable 和 JDK1.8 之前的 HashMap 的底層資料結構類似都是採用 陣列+連結串列 的形式,陣列是 HashMap 的主體,連結串列則是主要為了解決雜湊衝突而存在的;
  • 實現執行緒安全的方式(重要):在 JDK1.7 的時候,ConcurrentHashMap(分段鎖) 對整個桶陣列進行了分割分段(Segment),每一把鎖只鎖容器其中一部分資料,多執行緒訪問容器裡不同資料段的資料,就不會存在鎖競爭,提高併發訪問率。 到了 JDK1.8 的時候已經摒棄了 Segment 的概念,而是直接用 Node 陣列+連結串列+紅黑樹的資料結構來實現,併發控制使用 synchronized 和 CAS 來操作。(JDK1.6 以後 對 synchronized 鎖做了很多優化) 整個看起來就像是優化過且執行緒安全的 HashMap,雖然在 JDK1.8 中還能看到 Segment 的資料結構,但是已經簡化了屬性,只是為了相容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來保證執行緒安全,效率非常低下。當一個執行緒訪問同步方法時,其他執行緒也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 新增元素,另一個執行緒不能使用 put 新增元素,也不能使用 get,競爭會越來越激烈效率越低。

img

img

img

JDK1.8 的 ConcurrentHashMap 不在是 Segment 陣列 + HashEntry 陣列 + 連結串列,而是 Node 陣列 + 連結串列 / 紅黑樹。不過,Node 只能用於連結串列的情況,紅黑樹的情況需要使用 TreeNode。當衝突連結串列達到一定長度時,連結串列會轉換成紅黑樹。

ConcurrentHashMap 執行緒安全的底層實現

上面有示意圖。

  • JDK 1.7 的 ConcurrentHashMap

    首先將資料分為一段一段的儲存,然後給每一段資料配一把鎖,當一個執行緒佔用鎖訪問其中一個段資料時,其他段的資料也能被其他執行緒訪問。

    ConcurrentHashMap 是由 Segment 陣列結構和 HashEntry 陣列結構組成

    Segment 實現了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用於儲存鍵值對資料。

    static class Segment<K,V> extends ReentrantLock implements Serializable {
    }Copy to clipboardErrorCopied
    

    一個 ConcurrentHashMap 裡包含一個 Segment 陣列。Segment 的結構和 HashMap 類似,是一種陣列和連結串列結構,一個 Segment 包含一個 HashEntry 陣列,每個 HashEntry 是一個連結串列結構的元素,每個 Segment 守護著一個 HashEntry 陣列裡的元素,當對 HashEntry 陣列的資料進行修改時,必須首先獲得對應的 Segment 的鎖。

  • JDK 1.8 的 ConcurrentHashMap

    ConcurrentHashMap 取消了 Segment 分段鎖,採用 CAS 和 synchronized 來保證併發安全。資料結構跟 HashMap1.8 的結構類似,陣列+連結串列/紅黑二叉樹。Java 8 在連結串列長度超過一定閾值(8)時將連結串列(定址時間複雜度為 O(N))轉換為紅黑樹(定址時間複雜度為 O(log(N)))

    synchronized 只鎖定當前連結串列或紅黑二叉樹的首節點,這樣只要 hash 不衝突,就不會產生併發,效率又提升 N 倍。

Collections 工具類

排序

void reverse(List list)//反轉
void shuffle(List list)//隨機排序
void sort(List list)//按自然排序的升序排序
void sort(List list, Comparator c)//定製排序,由Comparator控制排序邏輯
void swap(List list, int i , int j)//交換兩個索引位置的元素
void rotate(List list, int distance)//旋轉。當distance為正數時,將list後distance個元素整體移到前面。當distance為負數時,將 list的前distance個元素整體移到後面Copy to clipboardErrorCopied

查詢、替換操作

int binarySearch(List list, Object key)//對List進行二分查詢,返回索引,注意List必須是有序的
int max(Collection coll)//根據元素的自然順序,返回最大的元素。 類比int min(Collection coll)
int max(Collection coll, Comparator c)//根據定製排序,返回最大元素,排序規則由Comparatator類控制。類比int min(Collection coll, Comparator c)
void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素。
int frequency(Collection c, Object o)//統計元素出現次數
int indexOfSubList(List list, List target)//統計target在list中第一次出現的索引,找不到則返回-1,類比int lastIndexOfSubList(List source, list target).
boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替換舊元素Copy to clipboardErrorCopied

更多幹貨請移步:https://antoniopeng.com

相關文章