Java集合(三)—List和Queue集合
目錄公眾號: 菜雞幹Java 歡迎關注
Java集合—List集合
與Set集合不同,List集合是有序,可重複的,而且預設以新增順序設定索引。List
子介面是繼承了Collection
介面,則可以使用其中的方法。
特別的是List
增加了根據索引插入、替換、刪除集合元素的方法,此外,Java8為List
介面添加了兩個預設方法:
- void replaceAll():根據指定規則重新設定List集合的所有元素
- void sort(Comparator c):根據引數對List集合的元素排序
List books = new ArrayList(); books.add(new String("ledon")); books.add(new String("Android")); books.sort((o1,o2)->((String)o1).length()-((String)o2).length()); //字串將由短到長排序 System.out.println(books); books.replaceAll(e->((String)e).length()); System.out.println(e);//[5,7]
值得注意的是:List
判斷兩個物件相等,只要通過equals
方法比較返回true即可,不像Set
集合,還需要判斷雜湊值是否相等來避免重複。
刪除元素時,List
會呼叫物件的equals
方法依次與集合元素比較,如果返回true,則會刪除該元素。如果重寫了equals
方法,使它總是返回true,則List總會刪除第一個元素。在使用set(index,object)
方法時,index不能超過集合的長度,也不能改變長度。
List不僅有iterator()
方法,還有listIterator()
方法,該方法返回一個ListIterator
物件,ListIterator
介面繼承了Iterator
介面,提供了專門的方法操作List
- boolean hasPrevious():返回該集合是否還有上一個元素
- Object previous():返回上一個元素
- void add(Object o):在指定位置插入一個元素
不難發現該介面還能向前迭代,不止能刪除元素,並且還能通過add()
方法,新增元素。
ArrayList和Vector
它們兩個封裝了 一個動態的Object[ ]陣列,允許再分配。ArrayList
及Vector
物件使用initialCapacity
引數來設定陣列的長度,當超出陣列容量時,initialCapacity
會自動增加,可使用ensureCapacity(int minCapacity)
方法一次性增加initialCapacity
。如果事先知道元素的個數,可指定初始大小;如果沒有指定初始容量,預設為10。
ArrayList
和Vector
提供了兩個方法重新分配Object[]
陣列:
- void ensureCapacity(int minCapacity):將
ArrayList
和Vector
集合的Object[]
陣列長度增加到大於或等於minCapacity值 - void trimToSize():調整
ArrayList
及Vector
的陣列長度為當前元素個數,減少佔用空間
ArrayList
和Vector
的用法幾乎完全相同,Vector
也是實現了List
介面,從JDK1.0
就有了,很古老!此外,ArrayList
是執行緒不安全的,原理一樣;但Vector
是執行緒安全的,即無需保證執行緒的同步性,因而Vector
的效能比ArrayList
低。但是還是用ArrayList
更多,要想執行緒安全,也可以把ArrayList
變成執行緒安全。
Stack類(Vector的子類)
翻譯過來就是“棧”,模擬進棧push
,出棧pop
等操作。作為集合的一種,它也是儲存物件(Object)的,有如下方法:
- Object peek():返回棧頂元素,但並不彈出該元素,元素還會在棧內
- Object pop():返回棧頂元素,並彈出棧
- void push(Object item):推元素進棧
Stack
繼承了Vector
,所以它也非常古老,執行緒安全、效能較差。後面還會介紹一種“棧”結構——ArrayDeque,它不僅實現了List
介面,還實現了Deque
介面,如果需要棧結構,可以使用它而不是Stack
。
固定長度的List
有一種運算元組的工具類Arrays
,該工具類提供了asList()
方法,該方法把一個數組或指定個數的物件換成一個List
集合,這個集合不是以上所介紹的集合類的例項,不是ArrayList
的,不是Vector
的,而是Arrays
的內部類ArrayList
的例項。Arrays.ArrayList
是一個固定長度的List
集合,不允許新增、刪除操作,只能遍歷訪問,否則程式將出現UnsupportedOperationException
異常。
Java集合-Queue集合
在Queue
介面中定義瞭如下的方法:
- void add(Object e):新增元素到隊尾
- boolean offer(Object e):將指定元素加入佇列的尾部,成功返回true
- Object element():獲取佇列頭部的元素,但不是刪除該元素
- Object remove():獲取頭部元素,並刪除該元素
- Object peek():獲取佇列頭部的元素,但不是刪除,如果為空返回null
- Object poll():獲取並刪除頭部元素,為空,返回null
Queue有一個PriorityQueue
實現類,除此外還有一個Deque
介面,代表雙端佇列,即兩端可以新增刪除元素。其實現類為ArrayDeque
和LinkedList
兩個實現類。
PriorityQueue類
PriorityQueue並不是一個標準的佇列,其儲存佇列的順序是重新排序了的(按元素的大小),顯然不符合佇列的規則。如果呼叫poll
方法,可以看到元素從小到大移出佇列。另外需要注意的是,PriorityQueue
不允許插入null元素!
它的排序有兩種,自然排序、定製排序,排序規則與TreeSet
類似:
- 自然排序:自然排序時,元素必須實現了
Comparable
介面,而且是同一類的例項。 - 定製排序:建立佇列時,傳入一個
Comparator
物件,該物件負責排序,但是不要求元素實現Comparable
介面
Deque介面與ArrayDeque
Deque
介面是Queue
的子介面,允許對佇列兩端進行操作,同時,還可以當作“棧”來使用,因為它還有pop
、push
方法。典型的實現類是ArrayDeque
,一個基於陣列的雙端佇列,在建立Deque
時,同樣可以指定一個numElement
元素個數引數,指定Object[ ]陣列的長度;如果不指定,則預設長度為16。
ArrayList
與ArrayDeque
的實現原理差不多,底層採用一個動態的、可再分配的陣列實現,初始化可指定初始長度等,當元素個數超出容量時,系統會重新分配一個Object[]
陣列儲存元素。
LinkedList類
LinkedList
實現了List
介面,是List
集合,還實現了Deque
介面,可以當雙端佇列使用,還能當"棧"使用。 但它的實現機制與ArrayList
、ArrayDeque
的不一樣,它兩是用陣列實現,而LinkedList
是以連結串列的形式來儲存元素,隨機訪問效能較差,但插入、刪除操作比較溜!
線性表效能分析
一般來說,陣列由一塊連續的記憶體來儲存資料,所以陣列隨機訪問效能好,類似的,以陣列為底層實現的類,隨機訪問效能都比較好;而連結串列的插入、刪除操作效能好。綜合來講,還是用ArrayList
比較妥。
-
如果需要遍歷:對於
ArrayList
,Vector
集合,使用隨機訪問方法遍歷即可;對於LinkedList
集合,採用Iterator
迭代器遍歷比較好。 -
如果經常要執行插入、刪除操作,可以使用
LinkedList
集合,而使用以陣列為底層的線性表要重新分配內部陣列大小,效能較差。 -
如果有多個執行緒同時訪問,可以使用工具類包裝成執行緒安全的集合。