天天看點

Java Review (二十七、集合----- List 集合)Java8 改進的List 接口和Listlterator 接口ArrayList 和 Vector 實作類LinkedList 實作類

文章目錄

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

相比較父接口 Collection,由于 List 是有序集合 , 是以 List 集合裡增加 了一些根據索引來操作集合元素的方法。

  • void add(int index, Object element): 将元素 element 插入到 List 集合的 index 處 。
  • boolean addAll(int index, Collection c): 将集合 c 所包含的所有元素都插入到 List 集合的 index處。
  • Object get(int index): 傳回集合 index 索引處的元素。
  • int indexOf(Object 0): 傳回對象 。 在 List 集合中第 一次出現的位置索引。
  • int lastlndexOf(Object 0): 返 回 對象 。 在 List 集合中最後 一 次出現的位置索引 。
  • Object remove(int index): 删除并傳回 index 索引處的元素 。
  • Object set(int index, Object element): 将 index 索引處的元素替換成 e lement 對象,傳回被替換的舊元素 。
  • List subList(int fromIndex, int toIndex): 傳回從索引 fromlndex (包含)到索引 to Index (不包含)處所有集合元素組成的子集合。

所有 的 List 實作類都可以調用這些方法來操作集合元素。與 Set 集合相比, List 增加了根據索引來插入、替換和删除集合元素 的方法。除此之外 , Java 8 還為 List 接口添加了如下兩個預設方法 :

  • void replaceAll(UnaryOperator operator): 根據 operator 指定的計算規則重新設定 List 集合的所有元素。
  • void sort(Comparator c): 根據 Comparator 參數對 List 集合的元素排序 。

下面程式示範了 List 集合的正常用法:

ListTest.java

public class ListTest
{
    public static void main(String[] args)
    {
        List books = new ArrayList();
        // 向books集合中添加三個元素
        books.add(new String("輕量級Java EE企業應用實戰"));
        books.add(new String("瘋狂Java講義"));
        books.add(new String("瘋狂Android講義"));
        System.out.println(books);
        // 将新字元串對象插入在第二個位置
        books.add(1 , new String("瘋狂Ajax講義"));
        for (int i = 0 ; i < books.size() ; i++ )
        {
            System.out.println(books.get(i));
        }
        // 删除第三個元素
        books.remove(2);
        System.out.println(books);
        // 判斷指定元素在List集合中位置:輸出1,表明位于第二位
        System.out.println(books.indexOf(new String("瘋狂Ajax講義"))); //①
        //将第二個元素替換成新的字元串對象
        books.set(1, new String("瘋狂Java講義"));
        System.out.println(books);
        //将books集合的第二個元素(包括)
        //到第三個元素(不包括)截取成子集合
        System.out.println(books.subList(1 , 2));
    }
}      

運作結果:

Java Review (二十七、集合----- List 集合)Java8 改進的List 接口和Listlterator 接口ArrayList 和 Vector 實作類LinkedList 實作類

①行代碼處,程式試圖傳回新字元串對象在 List集合中的位置,實際上 List 集合中并未包含該字元串對象 。 因為 List 集合添加宇符串對象時 ,添加的是通過 new 關鍵宇建立的新字元串對象,①行代碼處也是通過 new 關鍵宇建立的新字元串對象,兩個字元串顯然不是同一個對象,但 List 的 indexOf 方法依然可以傳回 1 。

List 判斷兩個對象相等隻要通過 equals()方法比較傳回 true 即可 。

ListTest2.java

class A
{
    public boolean equals(Object obj)
    {
        return true;
    }
}
public class ListTest2
{
    public static void main(String[] args)
    {
        List books = new ArrayList();
        books.add(new String("輕量級Java EE企業應用實戰"));
        books.add(new String("瘋狂Java講義"));
        books.add(new String("瘋狂Android講義"));
        System.out.println(books);
        // 删除集合中A對象,将導緻第一個元素被删除
        books.remove(new A());     // ①
        System.out.println(books);
        // 删除集合中A對象,再次删除集合中第一個元素
        books.remove(new A());     // ②
        System.out.println(books);
    }
}      
Java Review (二十七、集合----- List 集合)Java8 改進的List 接口和Listlterator 接口ArrayList 和 Vector 實作類LinkedList 實作類

執行①行代碼時 ,程式試圖删除一個 A 對象 , List 将會調用該A對象的equals()方法依次與集合元素進行比較,如果該 equalsO方法 以某個集合元素作為參數時傳回 true , List将會删除該元素——A 類重寫了 equalsO方法 , 該方法總是傳回 true。所 以每次從 List 集合中删除 A 對象時 ,總是删除 List 集合中的第一個元素 。

與 Set 隻提供了 一個 iterator()方法不同, List 還額外提供了 一個 listIterator()方法,該方法傳回 一個Listlterator 對象, ListIterator 接口繼承了Iterator 接口,提供了專門操作 List 的方法 。 ListIterator 接口在Iterator 接口基礎上增加了如下方法 。

  • boolean hasPreviousO: 傳回該法代器關聯的集合是否還有上一個元素 。
  • Object previous(): 傳回該疊代器的上一個元素。
  • void add(Object 0): 在指定位置插入一個元素 。
API: java.util.List java.util.ListIterator

ArrayList結構圖

ArrayList 和 Vector 類都是基于數組實作的 List 類,是以 ArrayList 和 Vector 類封裝了一個動态的、允許再配置設定的 Object[]數組 。 ArrayList 或 Vector 對象使用 initialCapacity 參數來設定該數組的長度, 當向 ArrayList 或 Vector 中添加元素超出了該數組的長度時,它們的 initialCapacity 會自動增加 。

ArrayList構造方法

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        // 如果傳入的初始容量大于0,就建立一個數組存儲元素
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        // 如果傳入的初始容量等于0,使用空數組EMPTY_ELEMENTDATA
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        // 如果傳入的初始容量小于0,抛出異常
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
    }
}      

對于通常的程式設計場景,程式員無須關心 ArrayList 或 Vector 的 initialCapacity 。 但如果向ArrayList或 Vector 集合中添加大 量 元素時,可使用ensureCapacity(int minCapacity) 方法一次性地增加initialCapacity 。 這可以減少重配置設定 的 次數 ,進而提高性能 。

如果開始就知道 ArrayList 或 Vector 集合需要儲存多少個元素,則可以在建立它們時就指定initialCapacity 大小 。 如果建立空的 ArrayList 或 Vector 集合時不指定 initialCapacity 參數 ,則 Object[] 數組的長度預設為 10 。

ArrayList屬性

/**
 * 預設容量
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 空數組,如果傳入的容量為0時使用
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 空數組,傳傳入容量時使用,添加第一個元素的時候會重新初始為預設容量大小
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * 存儲元素的數組
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * 集合中元素的個數
 */
private int size;      

除此之外,ArrayList 和 Vector 還提供了如下兩個方法來重新配置設定 Object[]數組:

  • void ensureCapacity(int minCapacity): 将 ArrayList 或 Vector 集合的 Object[]數組長度增加大于或等于 minCapacity 值。
  • void trimToSize(): 調整 ArrayList 或 Vector 集合 的 Object[]數組長度為 目前元素 的個數 。 調用該方法可減少 ArrayList 或 Vector 集合對象占用 的存儲空間 。

ArrayList 和 Vector 在用法上幾乎完全相同 ,Vector十分古老,那時候 Java 還沒有提供系統的集合架構,是以 Vector 裡提供了 一 些方法名很長的方法。

除此之外, ArrayList 和 Vector 的 顯著差別是 :

ArrayList 是線程不安全的,當多個線程通路同一個ArrayList 集合時,如果有超過一個線程修改了 ArrayList 集合,則程式必須于動保證該集合的同步性;

但 Vector 集合則是線程安全的,無須程式保證該集合的同步性。因為 Vector 是線程安全的,是以 Vector的性能比 ArrayList 的性能要低 。

java.util.ArrayList java.util.Vector

LinkedList結構圖

LinkedList 類是 List 接口的實作類 一它是一 個 List 集合 ,可以根據索引來随機通路集合中的元素 。

除此之外, LinkedList 還實作了 Deque 接口,可以被當成雙端隊列來使用,還可以被當成"棧"來使用 。

下面程式簡單示範了 LinkedList 集合的用法:

LinkedListTest.java

public class LinkedListTest
{
    public static void main(String[] args)
    {
        LinkedList books = new LinkedList();
        // 将字元串元素加入隊列的尾部
        books.offer("瘋狂Java講義");
        // 将一個字元串元素加入棧的頂部
        books.push("輕量級Java EE企業應用實戰");
        // 将字元串元素添加到隊列的頭部(相當于棧的頂部)
        books.offerFirst("瘋狂Android講義");
        // 以List的方式(按索引通路的方式)來周遊集合元素
        for (int i = 0; i < books.size() ; i++ )
        {
            System.out.println("周遊中:" + books.get(i));
        }
        // 通路、并不删除棧頂的元素
        System.out.println(books.peekFirst());
        // 通路、并不删除隊列的最後一個元素
        System.out.println(books.peekLast());
        // 将棧頂的元素彈出“棧”
        System.out.println(books.pop());
        // 下面輸出将看到隊列中第一個元素被删除
        System.out.println(books);
        // 通路、并删除隊列的最後一個元素
        System.out.println(books.pollLast());
        // 下面輸出:[輕量級Java EE企業應用實戰]
        System.out.println(books);
    }
}      

LinkedList 與 ArrayList 的實作機制完全不同:

  • ArrayList 内部以數組的形式來儲存集合中的元素 , 是以随機通路集合元素時有較好的性能;
  • 而 LinkedList 内部以連結清單的形式來儲存集合中的元素,是以随機通路集合元素時性能較差,但在插入、删除元素時性能比較出色(隻需改變指針所指的位址即可)。

雙向連結清單

Java Review (二十七、集合----- List 集合)Java8 改進的List 接口和Listlterator 接口ArrayList 和 Vector 實作類LinkedList 實作類

從連結清單删除元素

Java Review (二十七、集合----- List 集合)Java8 改進的List 接口和Listlterator 接口ArrayList 和 Vector 實作類LinkedList 實作類
java.util.LinkedList

參考

【1】:《瘋狂Java講義》

【2】:《Java核心技術 卷一》

【3】:

Java技術驿站:【死磕 Java 集合】— ArrayList源碼分析

【4】:

方志朋的專欄:Java基礎:Java容器之ArrayList

【5】:

Java技術驿站:【死磕 Java 集合】— LinkedList源碼分析

【6】:

方志朋的專欄:Java基礎:Java容器之LinkedList

【7】:

廖雪峰的官方網站:使用List