1. 程式人生 > 實用技巧 >持有物件(集合)

持有物件(集合)

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

1、基本概念

  • java容器類類庫的用途是“儲存物件”,並將其劃分為兩個不同的概念:

    Collection:一個獨立元素的序列,這些元素服從一條或多條規則。List必須按照插入順序儲存元素,而Set不能有重複元素。Queue按照排隊規則來確定物件產生的順序(通常與被插入的順序相同)。

    Map:一組成對的“鍵值對”物件,允許你使用鍵查詢值。

  • Collection介面概括了序列的概念——一種存放一組物件的方式。所有的Collection都可以用foreach語法遍歷。

2、新增一組元素

  • java.util包中Arrays和Collections類中都有很多實用方法。Arrays.asList()方法接受一個數組或是一個用逗號分隔的元素列表(使用可變引數),並將其轉換為一個List物件。Collections.addAll()方法接受一個Collection物件,以及一個數組或是一個用逗號分隔的列表,將元素新增到Collection中。

  • Collection.addAll()成員方法只能接受另一個Collection物件作為引數,因此它不如Arrays.asList()或Collections.addAll()靈活,這兩個方法使用的都是可變引數列表。

  • 直接使用Arrays.asList()的輸出當作List,在這種情況下,其底層表示的是陣列,因此不能調整大小。如果你試圖用add()或delete()方法在這種列表中新增或刪除元素,執行時會報錯。

  • Arrays.asList()中間可以插入一條“線索(引數型別)”,以告訴編譯器對於有Arrays.asList()產生的List型別,這稱為顯式型別引數說明。

3、容器的列印

  • java容器類庫中有兩種主要型別,區別在於容器中每個“槽”儲存的元素個數。Collection在每個槽中只能儲存一個元素,此類容器包括:List,它以特定的順序(插入順序)儲存一組元素;Set,元素不能重複;Queue,允許在容器的一端插入元素,並從另一端移除元素。Map在每個槽內儲存了兩個物件,即鍵和與之相關聯的值。

  • Collection打印出來的內容用方括號括住,每個元素用逗號分隔。Map則用大括號括住,鍵與值由等號聯絡。

  • ArrayList和LinkedList都是List型別。

  • HashSet、TreeSet和LinkedHashSet都是Set型別,每個相同的項只儲存一次,不同的Set實現儲存元素的方式不同。HashSet使用的是相當複雜的方式來儲存,是最快的獲取元素方式,儲存順序貌似並無實際意義。儲存順序重要,可以使用TreeSet,它按照比較結果的升序儲存物件;或者使用LinkedHashSet,它按照被新增順序儲存物件。

  • HashMap、TreeMap和LinkedHashMap都是Map型別,對於每個鍵,Map只接受儲存一個值。與HashSet一樣,HashMap也提供了最快查詢技術,也沒按照任何明顯的順序來儲存元素。TreeMap按照比較結果的升序儲存鍵,而LinkedHashMap則按照插入順序儲存鍵,同時還保留了HashMap的查詢速度。

4、List

  • List介面在Collection的基礎上添加了大量的方法,使得可以在List中間插入或移除元素。

  • 兩種型別的List:

    基本的ArrayList,它長於隨機訪問元素,但在List中間插入和移除元素時較慢。

    LinkedList,它用較低代價完成在List中間進行插入和刪除操作,提供了優化的順序訪問。LinkedList在隨機訪問方面相對較慢,但它的特性集較ArrayList更大。

  • 常用方法:

    contains(Object obj):用來確定某個物件是否在列表中。

    remove(Object obj):移除一個物件。

    indexOf(Object obj):返回該物件在List中所處位置的索引編號。

    subList(int beginIndex,int endIndex):從較大列表中創建出一個子列表。注:對所返回的子列表的修改會反映到初始列表中,反之亦然。

    containsAll(List<Object> list):用來確定子列表是否在較大列表中。如果在,即使使用Collections.sort(List<> list)或Collection.shuffle(List<> list)改變子列表中元素的順序,不會影響其結果。

    retainAll(List<?> list):有效的交集操作,保留兩個List中同時存在的元素。

removeAll(List<?> list):將從某個List中移除引數List中的所有元素。

set(int index,Object obj):在指定的索引處(第一個引數),用第二個引數替換這個位置的元素。

addAll(List<?> list):過載的Collection介面中的方法,可以從中間插入(Collection中的addAll()方法是追加到列表尾)。

clear():移除列表中的所有元素。

isEmpty():判斷列表是否為空。

toArray():將任意的Collection轉換為一個數組。

5、迭代器

  • java的Iterator只能單向移動,這個Iterator只能用來:

    使用方法iterator()要求容器返回一個Iterator。Iterator將準備好返回序列的第一個元素。

    使用next()獲得序列中的下一個元素。

使用hasNext()檢查序列中是否還有元素。

使用remove()將迭代器新近返回的元素刪除。

  • 只是向前遍歷List,並不打算修改List物件本身,foreach語法顯得更加簡潔。

  • Iterator移除由next()產生的最後一個元素,意味著在呼叫remove()之前必須先呼叫next()。

  • 迭代器統一了對容器的訪問方式。

  • ListIterator是一個更加強大的Iterator的子型別,只能用於各種List類的訪問。通過呼叫listIterator()方法產生一個指向List開始處的ListIterator,並且還可以通過呼叫listIterator(int n)方法建立一個一開始指向列表索引為n的元素處的ListIterator。

  • ListIterator和Iterator的區別:

    ListIterator有add()方法,可以向List中新增物件,而Iterator不能
    ListIterator和Iterator都有hasNext()和next()方法,可以實現順序向後遍歷,但是ListIterator有hasPrevious()和previous()方法,可以實現逆向(順序向前)遍歷。Iterator就不可以。
    ListIterator可以定位當前的索引位置,nextIndex()和previousIndex()可以實現。Iterator沒有此功能。
    都可實現刪除物件,但是ListIterator可以實現物件的修改,set()方法可以實現。Iterator僅能遍歷,不能修改。

6、LinkedList

  • LinkedList添加了可以使其用作棧(Stack)、佇列(Queue)或雙端佇列的方法:

    getFirst()和element()完全一樣,都返回列表頭(第一個元素),而並不移除它,如果List為空,則丟擲NoSuchElementException異常。peek()方法與這兩方法稍有差異,列表為空時返回null。

removeFirst()和remove()也是完全一樣的,它們移除並返回列表的頭,而在列表為空時丟擲NoSuchElementException。poll()稍有差異,它在列表為空時返回null。

addFirst()在列表的開始位置插入一個元素。

offer()、add()、addLast() 相同,它們都將某個元素插入到列表的尾端。

removeLast()移除並返回列表的最後一個元素。

  • 在LinkedList的基礎上新增offer()、element()、peek()、poll()和remove()方法,使其成為一個Queue實現。

7、Stack

  • 棧通常是指“後進先出”的容器。

  • LinkedList具有能夠直接實現棧的所有功能方法,因此可以直接將LinkedList作為棧使用。

174853_NOqU_570654.jpg

注:peek()方法將提供棧頂元素,但是並不將其從棧頂移除,而pop()將移除並返回棧頂元素。

8、Set

  • Set不儲存重複的元素。Set具有與Collection完全一樣的介面,沒有新增任何額外的功能,實際上Set就是Collection,只是行為不同。

  • Set的實現具有不同的元素儲存方式。TreeSet將元素儲存在紅-黑樹的資料結構中,而HashSet使用的是雜湊函式。LinkedHashSet因為查詢速度的原因也使用了雜湊,但看來它使用了連結串列來維護元素的插入順序。

9、Map

  • containsKey()和containsValue(),檢視Map是否包含某個鍵或某個值。

  • keySet()方法返回Map中所有鍵組成的Set。

10、Queue

  • 佇列是一個典型的先進先出(FIFO)的容器。LinkedList提供了方法以支援佇列的行為,並且它實現了Queue介面,因此LinkedList可以看作Queue的一種實現。

  • 與Queue相關的方法提供了完整而獨立的功能,即,對於Queue所繼承的Collection,再不需要使用它任何方法的情況下,就可以擁有一個可用的Queue。

  • PriorityQueue(優先順序佇列),宣告下一個彈出的元素是最需要的元素(具有最高優先順序)。在PriorityQueue上呼叫offer()方法來插入一個物件時,這個物件會在佇列中被排序,預設的排序將使用物件在佇列中的自然順序,也可以通過自己提供Comparator來修改這個順序。

  • Collection.reverseOrder()產生反序的Comparator。

11、Collection和Iterator

  • Collection介面和Iterator都可以與底層特定容器實現解耦。當一個類是實現了Collection的類時,可以使用foreach結構,從而使程式碼更清晰。但是實現一個不是Collection的外部類時,讓它去實現Collection介面麻煩,使用Iterator更方便。

12、foreach與迭代器

  • foreach語法主要用於陣列,但也可以應用於任何Collection物件(你建立的任何實現Iterable的類,都可以將它用於foreach語句中)。

  • Arrays.asList()產生的List物件會使用底層陣列作為其物理實現。只要你執行的操作會修改這個List,並且你不想原來的陣列被修改,那麼就應該在另一個容器中建立一個副本。

13、總結

  • Vector:
      用ArrayList代替Vector。Vector是執行緒安全的,而有的時候我們確實希望在多執行緒的情況下使用列表,那麼這個時候我們可以利用Collections這個類當中為我們提供的synchronizedList(List list),它可以返回一個執行緒安全的同步的列表,還提供了返回同步的Collections。

    Hashtable:
      用HashMap代替Hashtable。Hashtable是執行緒安全的,而有的時候我們確實希望在多執行緒的情況下使用HashMap,那麼這個時候我們可以利用Collections這個類當中為我們提供的synchronizedMap(Map<K,V> m),它可以返回一個執行緒安全的同步的HashMap

    Stack:
      用LinkedList代替Stack。當初在設計Stack的時候就有一些潛在的問題,它是從Vector繼承而來,對於一個棧來說,它只能是最後放進去的元素,要先出來,但是它繼承自Vector,而Vector中有一個方法叫做elementAt(int index),而不能說是通過這個索引index去任意的獲得一個元素。結果它就有了這個奇怪的特性,提倡應該自己利用LinkedList去實現一個stack。

122805_h0GY_570654.jpg

其實只有四種容器:Map、List、Set和Queue,它們各有兩到三個實現版本。常用的容器用黑色粗線框表示。點線框表示介面,實線框表示普通類。帶有空心箭頭的點線表示一個特定的類實現了一個介面,實心箭頭表示某個類可以生成箭頭所指向類的物件。

123657_Ny6I_570654.jpg

轉載於:https://my.oschina.net/90liusq/blog/314645