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,增加了如下方法(類似Iterator的方法):

  • boolean hasPrevious():返回該集合是否還有上一個元素
  • Object previous():返回上一個元素
  • void add(Object o):在指定位置插入一個元素

不難發現該接口還能向前迭代,不止能刪除元素,並且還能通過add()方法,添加元素。

ArrayList和Vector

它們兩個封裝了 一個動態的Object[ ]數組,允許再分配。ArrayListVector對象使用initialCapacity參數來設置數組的長度,當超出數組容量時,initialCapacity會自動增加,可使用ensureCapacity(int minCapacity)方法一次性增加initialCapacity。如果事先知道元素的個數,可指定初始大小;如果沒有指定初始容量,默認為10。

ArrayListVector提供了兩個方法重新分配Object[]數組:

  • void ensureCapacity(int minCapacity):將ArrayListVector集合的Object[]數組長度增加到大於或等於minCapacity值
  • void trimToSize():調整ArrayListVector的數組長度為當前元素個數,減少占用空間

ArrayListVector的用法幾乎完全相同,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接口,代表雙端隊列,即兩端可以添加刪除元素。其實現類為ArrayDequeLinkedList兩個實現類。

PriorityQueue類

PriorityQueue並不是一個標准的隊列,其保存隊列的順序是重新排序了的(按元素的大小),顯然不符合隊列的規則。如果調用poll方法,可以看到元素從小到大移出隊列。另外需要注意的是,PriorityQueue不允許插入null元素!

它的排序有兩種,自然排序、定制排序,排序規則與TreeSet類似:

  • 自然排序:自然排序時,元素必須實現了Comparable接口,而且是同一類的實例。
  • 定制排序:創建隊列時,傳入一個Comparator對象,該對象負責排序,但是不要求元素實現Comparable接口

Deque接口與ArrayDeque

Deque接口是Queue的子接口,允許對隊列兩端進行操作,同時,還可以當作“棧”來使用,因為它還有poppush方法。典型的實現類是ArrayDeque,一個基於數組的雙端隊列,在創建Deque時,同樣可以指定一個numElement元素個數參數,指定Object[ ]數組的長度;如果不指定,則默認長度為16。

ArrayListArrayDeque的實現原理差不多,底層采用一個動態的、可再分配的數組實現,初始化可指定初始長度等,當元素個數超出容量時,系統會重新分配一個Object[]數組儲存元素。

LinkedList類

LinkedList實現了List接口,是List集合,還實現了Deque接口,可以當雙端隊列使用,還能當"棧"使用。 但它的實現機制與ArrayListArrayDeque的不一樣,它兩是用數組實現,而LinkedList是以鏈表的形式來保存元素,隨機訪問性能較差,但插入、刪除操作比較溜!

線性表性能分析

一般來說,數組由一塊連續的內存來保存數據,所以數組隨機訪問性能好,類似的,以數組為底層實現的類,隨機訪問性能都比較好;而鏈表的插入、刪除操作性能好。綜合來講,還是用ArrayList比較妥。

  • 如果需要遍歷:對於ArrayListVector集合,使用隨機訪問方法遍歷即可;對於LinkedList集合,采用Iterator迭代器遍歷比較好。

  • 如果經常要執行插入、刪除操作,可以使用LinkedList集合,而使用以數組為底層的線性表要重新分配內部數組大小,性能較差。

  • 如果有多個線程同時訪問,可以使用工具類包裝成線程安全的集合。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM