公眾號: 菜雞干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
,增加了如下方法(類似Iterator的方法):
- 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
集合,而使用以數組為底層的線性表要重新分配內部數組大小,性能較差。 -
如果有多個線程同時訪問,可以使用工具類包裝成線程安全的集合。