Collection及其子類ArrayList和LinkedList和Vector的底層實現和區別

2020-08-09 10:18:00

點選上方「羅曉勝」,馬上關注,您的支援對我幫助很大

 

上期文章

 

 

 

/   前言   /

 

在使用java的時候,我們都會遇到使用集合(collection)的時候,但是java api提供了多種集合的實現。

像我們常使用的list,arraylist,set,總的說來,java api中所用的集合類,都是實現了collection介面

 

/   正文   /

 

數據結構

線性表,鏈表,雜湊表是常用的數據結構,在進行Java開發時,JDK已經爲我們提供了一系列相應的類來實現基本的數據結構。這些類均在java.util包中。

  • Java集合工具包位於Java.util包下,包含了很多常用的數據結構,如陣列、鏈表、棧、佇列、集合、雜湊表等。

  • 組成:

    • List列表

    • Set集合

    • Collection

    • Map對映

    • 迭代器(Iterator、Enumeration)

    • 工具類(Arrays、Collections)

Java集合類的整體框架如下:

  • 集合類主要分爲兩大類:

  • Collection:繼承了超級介面Iterable,是List、Set等集合高度抽象出來的介面,它包含了這些集合的基本操作

  • List: List介面通常表示一個列表(陣列、佇列、鏈表、棧等),其中的元素可以重複,常用實現類爲ArrayList和LinkedList,另外還有不常用的Vector。另外,LinkedList還是實現了Queue介面,因此也可以作爲佇列使用。

  • Set: Set介面通常表示一個集合,其中的元素不允許重複(通過hashcode和equals函數保證),常用實現類有HashSet和TreeSet,HashSet是通過Map中的HashMap實現的,而TreeSet是通過Map中的TreeMap實現的。另外,TreeSet還實現了SortedSet介面,因此是有序的集合(集閤中的元素要實現Comparable介面,並覆寫Compartor函數才行)。

  • 說明:抽象類AbstractCollection、AbstractList和AbstractSet分別實現了Collection、List和Set介面,這就是在Java集合框架中用的很多的適配器設計模式,用這些抽象類去實現介面,在抽象類中實現介面中的若幹或全部方法,這樣下面 下麪的一些類只需直接繼承該抽象類,並實現自己需要的方法即可,而不用實現介面中的全部抽象方法。

 

  • Map

    • Map是一個對映介面,其中的每個元素都是一個key-value鍵值對,同樣抽象類AbstractMap通過適配器模式實現了Map介面中的大部分函數,TreeMap、HashMap、WeakHashMap等實現類都通過繼承AbstractMap來實現,另外,不常用的HashTable直接實現了Map介面,它和Vector都是JDK1.0就引入的集合類。

 

  • 迭代器:Iterator是遍歷集合的迭代器(不能遍歷Map,只用來遍歷Collection),Collection的實現類都實現了iterator()函數,它返回一個Iterator物件,用來遍歷集合,ListIterator則專門用來遍歷List。而Enumeration則是JDK1.0時引入的,作用與Iterator相同,但它的功能比Iterator要少,它只能在Hashtable、Vector和Stack中使用。

  • 工具類:Arrays和Collections是用來運算元組、集合的兩個工具類,例如在ArrayList和Vector中大量呼叫了Arrays.Copyof()方法,而Collections中有很多靜態方法可以返回各集合類的synchronized版本,即執行緒安全的版本,當然了,如果要用執行緒安全的結合類,首選Concurrent併發包下的對應的集合類。


Collection

  1. 是一個最基本的集合介面,也是一個泛型的介面

  2. 繼承了超級介面Iterable,子介面:List、Set、Queue等

  3. 每個Collection的物件包含了一組物件

  4. 所有的實現類都有兩個構造方法,一個是無參構造方法,第二個是用另外一個Collection物件作爲構造方法的參數

  5. 遍歷Collection使用Iterator迭代器實現

  6. retainAll(collection),AddAll(),removeAll(c)分別對應了集合的交併差運算

  7. 沒有具體的直接實現,但提供了更具體的子介面,如Set、List等

Collection簡介

  • 一個Collection代表一組Object,即Collection的元素(Elements),一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。

  • Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的「子介面」如List和Set。

如何遍歷Collection中的每一個元素?

  • 不論Collection的實際型別如何,它都支援一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一存取Collection中每一個元素,程式碼如下:

	Iterator it = collection.iterator(); // 獲得一個迭代子
    while(it.hasNext())  
    {
        Object obj = it.next(); // 得到下一個元素
    }
  • 其他方法

    • retainAll(Collection<? extends E> c)**:保留,交運算

    • addAll(Collection<? extends E> c)**:新增,並運算

    • removeAll(Collection<? extends E> c)**:移除,減運算


List

  • 是一個介面

  • 繼承的介面:Collection

  • 間接繼承的介面:Iterable

  • List是有序的Collection

    • 可以對每個元素的插入位置進行精準控制

    • 可以根據索引存取元素

  • 和Set介面的最大區別是,List允許重複值,Set不能

  • 它的直接實現類有ArrayList,LinkedList,Vector等

  • List有自己的迭代器ListIterator,可以通過這個迭代器進行逆序的迭代,以及用迭代器設定元素的值

  • 如果元素包含自身,equals()和hashCode()不再是良定義的

  • 實現類:ArrayList、LinkedList、Vector等

List方法

boolean add(E e): 新增到末尾
void add(int index, E e): 新增到指定位置

E set(int index, E e): 設定指定位置的元素,返回一個E
get(int index): 獲得指定位置的元素

Iterator iterator()
ListIterator listIterator()
ListIterator listIterator(int index)

int indexOf(E e)
int lastIndexOf(E e)

List subList(int fromIndex, int toIndex)

子類介紹

  1. ArrayList

    • 實現的介面:List、Collectin、Iterable、Serializable、Cloneable、RandomAccess

    • 子類:AttributeList、RoleList、RoleUnresolvedList

    • ArrayList是一個順序表,大小可變。當更多的元素加入到ArrayList中時,其大小將會動態的增長

    • 內部的元素可以直接通過get與set方法進行存取,因爲ArrayList本質上就是一個數組

    • 但速度較快,ArrayList相比LinkedList在查詢和修改元素上比較快,但是在新增和刪除上比LinkedList慢

    • ArrayList和LinkedList一樣,不具備執行緒同步的安全性,Vector執行緒安全

    • ArrayList、Vector底部都是採用陣列實現的

    • 第一次定義的時候沒有指定陣列的長度則長度是0,在第一次新增的時候判斷如果是空則追加10。

    • 擴容機制 機製:ArrayList每次對size增長50%.

  2. LinkedList

    • 是一個雙鏈表

    • 它還是佇列、雙端佇列,可以用作堆疊

    • 和ArrayList一樣,不具有執行緒安全性

    • 在新增和刪除元素時具有比ArrayList更好的效能.但在get與set方面弱於ArrayList.當然,這些對比都是指數據量很大或者操作很頻繁的情況下的對比,如果數據和運算量很小,那麼對比將失去意義。

    • LinkedList還實現了Queue介面,所以它還是一個雙端佇列,該介面比List提供了更多的方法,包括offer(),peek(),poll等

  3. Vector(執行緒安全)

    • 執行緒安全

    • 和ArrayList類似,但屬於強同步類。

    • 如果你的程式本身是執行緒安全的(thread-safe,沒有在多個執行緒之間共用同一個集合/物件),那麼使用ArrayList是更好的選擇。

    • Vector和ArrayList在更多元素新增進來時會請求更大的空間。Vector每次請求其大小的雙倍空間,而ArrayList每次對size增長50%.

#####ArrayList容量是如何變化的 在原始碼中:

private transient Object[] elementData;

用於儲存物件。它會隨着元素的新增而改變大小。在下面 下麪的敘述中,容量指的是elementData.length,而不是size。

size不是容量,ArrayList物件佔用的記憶體不是由size決定的。size的大小在每次呼叫add(E e)方法時加1。如果是呼叫ArrayList(Collection<? extends E> c)構造方法,則size的初始值爲c

  • 如果在初始化時,沒有指定大小,則容量大小爲0。

  • 當大小爲0時,第一次新增元素容量大小變爲10。

  • 之後每次新增時,會先確保容量是否夠用

  • 如果不夠用,每次增加的容量爲 newCapacity = oldCapacity + (oldCapacity >> 1);即,每次增加爲原來的1.5倍。

擴容方法

void ensureCapacity(int minCapacity) 設定容量能容納下minCapacity個元素


Set

  • 是一個泛型介面

  • 繼承了介面Collection

  • 子介面:NavigableSet、SortedSet

  • 子類:EnumSet、HashSet、LinkedHashSet、TreeSet、AbstractSet等

  • 不允許重複元素

  • 兩個注意點:

    1. Set中的元素的類,必須有一個有效的equals方法。

    2. 對Set的構造方法,傳入的Collection物件中重複的元素會只留下一個


Queue

  • 是個佇列,也是是一個泛型介面

  • 父介面:Collection

  • 子介面:Deque

  • 插入、提取、檢查操作都存在兩種形式,一種在操作失敗後返回特殊值,一種拋出異常

Queue方法

  1. boolean add(E e)和 boolean offer(E e)新增元素 失敗時,add()拋出異常,offer()返回false

  2. E element()和E peek()獲取但不移除 失敗時,element拋出異常,peek()返回null

  3. E remove()和E poll()獲取並移除 失敗時,remove()拋出異常,poll()返回null

Queue子類介紹

  • Deque

    • 雙端佇列

    • 可以實現佇列。也可以用作棧

 

/   總結   /

 

本文主要講了Collection底層的分析和用法,看看有沒有你常用但是卻不知道的知識。

 

往期推薦:

如何入門做軟件開發

爲什麼我不推薦入行程式設計師

做全棧開發很難嗎

關注我的公衆號,學習技術或投稿

長按上圖,識別圖中二維條碼即可關注