java中的集合類型的使用

Collection

├List

│├LinkedList

│├ArrayList (異步,線程不安全,空間用完時自動增長原容量一半)

│└Vector (同步,線程安全,空間用完時自動增長原容量一倍)

│ └Stack

└Set

  ├HashSet

  └TreeSet

Map

├Hashtable

├HashMap

├WeakHashMap

└TreeMap

 

Map接口:
    |
    + -- WeakHashMap: 以弱鍵 實現的基於哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條
    |      目。更精確地說,對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成爲可終止的,被終
    |      止,然後被回收。丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行爲與其他的 Map 實現有所不同。此實現
    |      不是同步的。
    |
    + -- TreeMap:該映射根據其鍵的自然順序進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的
    |    構造方法。此實現不是同步的。
    |
    + -- HashMap:基於哈希表的 Map 接口的實現。此實現提供所有可選的映射操作,並允許使用 null 值和 null 鍵。(除了      
    |        非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順   
    |       序恆久不變。此實現不是同步的。
    |
    +-- SortedMap: 進一步提供關於鍵的總體排序 的 Map。該映射是根據其鍵的自然順序進行排序的,或者根據通常在創建有
         序映射時提供的 Comparator 進行排序。對有序映射的 collection 視圖(由 entrySet、keySet 和 values 方法返回
         )進行迭代時,此順序就會反映出來。要採用此排序方式,還需要提供一些其他操作(此接口是 SortedSet 的對應映
         射)。

 

Collection接口:
    |
    + -- Set接口:一個不包含重複元素的 collection。更正式地說,set 不包含滿足 e1.equals(e2) 的元素對 e1 和 e2,並
    |      |     且最多包含一個 null 元素。正如其名稱所暗示的,此接口模仿了數學上的 set 抽象。
    |      |
    |      + -- HashSet:此類實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證 set 的迭代順序;
    |      |    特別是它不保證該順序恆久不變。此類允許使用 null 元素。此類爲基本操作提供了穩定性能,此實現不是同
    |      |    步的。
    |      |
    |      + -- LinkedHashSet:具有可預知迭代順序的 Set 接口的哈希表和鏈接列表實現。此實現與 HashSet 的不同之外在
    |      |    於,後者維護着一個運行於所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,即按照將元素插入到 set
    |      |    中 的順序(插入順序)進行迭代。注意,插入順序不 受在 set 中重新插入的 元素的影響。此實現不是同步
    |      |    的。
    |      |
    |      + -- TreeSet:基於 TreeMap 的 NavigableSet 實現。使用元素的自然順序對元素進行排序,或者根據創建 set 時
    |           提供的 Comparator 進行排序,具體取決於使用的構造方法。此實現爲基本操作(add、remove 和 contains)
    |           提供受保證的 log(n) 時間開銷。此實現不是同步的。
    |
    + -- List接口:有序的 collection(也稱爲序列)。此接口的用戶可以對列表中每個元素的插入位置進行精確地控制。用戶
           |      可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。
           |
           + -- ArrayList:List 接口的大小可變數組的實現。實現了所有可選列表操作,並允許包括 null 在內的所有元素。
           |    除了實現 List 接口外,此類還提供一些方法來操作內部用來存儲列表的數組的大小。(此類大致上等同於
           |    Vector 類,除了此類是不同步的。)每個 ArrayList 實例都有一個容量。該容量是指用來存儲列表元素的數
           |    組的大小。它總是至少等於列表的大小。隨着向 ArrayList 中不斷添加元素,其容量也自動增長。並未指定增
           |    長策略的細節,因爲這不只是添加元素會帶來分攤固定時間開銷那樣簡單。此實現不是同步的。
           |
           + -- LinkedList:List 接口的鏈接列表實現。實現所有可選的列表操作,並且允許所有元素(包括 null)。除了實
           |    現 List 接口外,LinkedList 類還爲在列表的開頭及結尾 get、remove 和 insert 元素提供了統一的命名方
           |    法。這些操作允許將鏈接列表用作堆棧、隊列或雙端隊列。提供先進先出隊列操作(FIFO)。此實現不是同步的。
           |
           + -- Vector:Vector 類可以實現可增長的對象數組。與數組一樣,它包含可以使用整數索引進行訪問的組件。但是
                ,Vector 的大小可以根據需要增大或縮小,以適應創建 Vector 後進行添加或移除項的操作。此實現是同步的.

 

1.       Collection的功能

下面這張表給出了Collection的所有功能,也就是你能用Set和List做什麼事(不包括從Object自動繼承過來的方法)。(List還有一些額外的功能。)Map不是繼承Collection的,所以我們會區別對待。

boolean add(Object):確保容器能持有你傳給它的那個參數。如果沒有把它加進去,就返回false。(這是個“可選”的方法,本章稍後會再作解釋。)
    boolean addAll(Collection):加入參數Collection所含的所有元素。只要加了元素,就返回true。
    void clear():清除容器所保存的所有元素。(“可選”)
    boolean contains(Object):如果容器持有參數Object,就返回true。
    boolean containsAll(Collection):如果容器持有參數Collection所含的全部元素,就返回true。
    boolean isEmpty():如果容器裏面沒有保存任何元素,就返回true。
    Iterator iterator():返回一個可以在容器的各元素之間移動的Iterator。
    boolean removeAll(Collection):刪除容器裏面所有參數Collection所包含的元素。只要刪過東西,就返回true。(“可選”)
    boolean retainAll(Collection):只保存參數Collection所包括的元素(集合論中“交集”的概念)。如果發生過變化,則返回true。(“可選”)
    int size():返回容器所含元素的數量。
    Object[] toArray():返回一個包含容器中所有元素的數組。
    Object[] toArray(Object[] a):返回一個包含容器中所有元素的數組,且這個數組不是普通的Object數組,它的類型應該同參數數組a的類型相同(要做類型轉換)。
    注意,這裏沒有能進行隨機訪問的get()方法。這是因爲Collection還包括Set。而Set有它自己的內部順序(因此隨即訪問事毫無意義的)。所以如果你要檢查Collection的元素,你就必須使用迭代器。

2.List的功能

List的基本用法事相當將但的。雖然絕大多數時候,你只是用add()加對象,用get()取對象,用iterator()獲取這個序列的Iterator,但List還有一些別的很有用的方法。
  實際上有兩種List:擅長對元素進行隨機訪問的,較常用的ArrayList,和更強大的LinkedList。LinkedList不是爲快速的隨機訪問而設計的,但是它卻有一組更加通用的方法。
   Lisk(接口):List的最重要的特徵就是有序;它會確保以一定的順序保存元素。List在Collection的基礎上添加了大量方法,使之能在序列中間插入和刪除元素。(只對LinkedList推薦使用。)List可以製造ListIterator對象,你除了能用它在List的中間插入和刪除元素之外,還能用它沿兩個方法遍歷List。
   ArrayList*:一個用數組實現的List。能進行快速的隨機訪問,但是往列表中間插入和刪除元素的時候比較慢。ListIterator只能用在反向遍歷ArrayList的場合,不要用它來插入和刪除元素,因爲相比LinkedList,在ArrayList裏面用ListIterator的系統開銷比較高。
   LinkedList:對順序訪問進行了優化。在List中間插入和刪除元素的代價也不高。隨機訪問的速度相對較慢。(用ArrayList吧。)此外它還有addFirst(),addLast(),getFirst(),getLast(),removeFirst()和removeLast()等方法(這些方法,接口和基類均未定義),你能把它當成棧(stack),隊列(queue)或雙向隊列(deque)來用。
   記住,容器只是一個存儲對象的盒子。如果這個笑盒子能幫你解決所有的問題,那你就用不着取管它事怎麼實現的(在絕大多數情況下,這是使用對象的基本概念)。如果開發環境裏面還有一些別的,會造成固定的性能開銷的因素存在,那麼ArrayList和LinkedList之間的性能差別就會變得不那麼重要了。你只需要它們中的一個,你甚至可以想象有這樣一種“完美”的抽象容器;它能根據用途,自動地切換其底層的實現。

 

用LinkedList做一個棧
“棧(stack)”有時也被稱爲“後進先出”(LIFO)的容器。就是說,最後一個被“壓”進棧中的東西,會第一個“彈”出來。同其他Java容器一樣,壓進去和彈出來的東西都是Object,所以除非你只用Object的功能,否則就必須對彈起來的東西進行類型轉換。
LinkedList的方法能直接實現棧的功能,所以你完全可以不寫Stack而直接使用LinkedList。
如果你只想要棧的功能,那麼繼承就不太合適了,因爲繼承出來的是一個擁有LinkedList的所有方法的類。

 

用LinkedList做一個隊列
隊列(queue)是一個“先進先出”(FIFO)容器。也就是,你把一端把東西放進去,從另一端把東西取出來。所以你放東西的順序也就是取東西的順序。LinkedList有支持隊列的功能的方法,所以它也能被當作Queue來用。
還能很輕易地用LinkedList做一個deque(雙向隊列)。它很像隊列,只是你可以從任意一端添加和刪除元素。

 

Vector類
  Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的Iterator是同一接口,但是,因爲Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。

Stack 類
  Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否爲空,search方法檢測一個元素在堆棧中的位置。Stack剛創建後是空棧。

3.Set的功能
Set的接口就是Collection的,所以不像那兩個List,它沒有額外的功能。實際上Set確確實實就是一個Collection--只不過行爲方式不同罷了。(這是繼承和多態性的完美運用:表達不同地行爲。)Set會拒絕持有多個具有相同值的對象的實例(對象的“值”又是由什麼決定的呢?這個問題比較複雜,我們以後會講)。
Set(接口):加入Set的每個元素必須是唯一的;否則,Set是不會把它加進去的。要想加進Set,Object必須定義equals(),這樣才能標明對象的唯一性。Set的接口和Collection的一摸一樣。Set的接口不保證它會用哪種順序來存儲元素。
HashSet*:爲優化查詢速度而設計的Set。要放進HashSet裏面的Object還得定義hashCode()。
TreeSet:是一個有序的Set,其底層是一顆樹。這樣你就能從Set裏面提取一個有序序列了。
LinkedHashSet(JDK 1.4):一個在內部使用鏈表的Set,既有HashSet的查詢速度,又能保存元素被加進去的順序(插入順序)。用Iterator遍歷Set的時候,它是按插入順序進行訪問的。
HashSet保存對象的順序是和TreeSet和LinkedHashSet不一樣的。這是因爲它們是用不同的方法來存儲和查找元素的。(TreeSet用了一種叫紅黑樹的數據結構【red-black tree data structure】來爲元素排序,而HashSet則用了“專爲快速查找而設計”的散列函數。LinkedHashSet在內部用散列來提高查詢速度,但是它看上去像是用鏈表來保存元素的插入順序的。)你寫自己的類的時候,一定要記住,Set要有一個判斷以什麼順序來存儲元素的標準,也就是說你必須實現 Comparable接口,並且定義compareTo()方法。

 

SortedSet
SortedSet(只有TreeSet這一個實現可用)中的元素一定是有序的。這使得SortedSet接口多了一些方法:
Comparator comparator():返回Set鎖使用的Comparator對象,或者用null表示它使用Object自有的排序方法。
Object first():返回最小的元素。
Object last():返回最大的元素。
SortedSet subSet(fromElement, toElement):返回Set的子集,其中的元素從fromElement開始到toElement爲止(包括fromElement,不包括toElement)。
SortedSet headSet(toElement):返回Set的子集,其中的元素都應小於toElement。
SortedSet headSet(toElement):返回Set的子集,其中的元素都應大於fromElement。
注意,SortedSet意思是“根據對象的比較順序”,而不是“插入順序”進行排序。

4.Map的功能
ArrayList能讓你用數字在一愕嘎對象序列裏面進行選擇,所以從某種意義上講,它是將數字和對象關聯起來。但是,如果你想根據其他條件在一個對象序列裏面進行選擇的話,那又該怎麼做呢?棧就是一個例子。它的標準是“選取最後一個被壓入棧的對象”。我們常用的術語map,dictionary,或 associative array就是一種非常強大的,能在序列裏面進行挑選的工具。從概念上講,它看上去像是一個ArrayList,但它不用數字,而是用另一個對象來查找對象!這是一種至關重要的編程技巧。
這一概念在Java中表現爲Map。put(Object key, Object value)方法會往Map裏面加一個值,並且把這個值同鍵(你查找時所用的對象)聯繫起來。給出鍵之後,get(Object key)就會返回與之相關的值。你也可以用containsKey()和containsValue()測試Map是否包含有某個鍵或值。
Java標準類庫裏有好幾種Map:HashMap,TreeMap,LinkedHashMap,WeakHashMap,以及 IdentityHashMap。它們都實現了Map的基本接口,但是在行爲方式方面有着明顯的詫異。這些差異體現在,效率,持有和表示對象pair的順序,持有對象的時間長短,以及如何決定鍵的相等性。
性能時Map所要面對的一個大問題。如果你知道get()時怎麼工作的,你就會發覺(比方說)在ArrayList裏面找對象會是相當慢的。而這正是 HashMap的強項。它不是慢慢地一個個地找這個鍵,而是用了一種被稱爲hash code的特殊值來進行查找的。散列(hash)時一種算法,它會從目標對象當中提取一些信息,然後生成一個表示這個對象的“相對獨特”的int。 hashCode()是Object根類的方法,因此所有Java對象都能生成hash code。HashMap則利用對象的hashCode()來進行快速的查找。這樣性能就有了急劇的提高。
Map(接口):維持鍵--值的關係(既pairs),這樣就能用鍵來找值了。
HashMap*:基於hash表的實現。(用它來代替Hashtable。)提供時間恆定的插入與查詢。在構造函數種可以設置hash表的capacity和load factor。可以通過構造函數來調節其性能。
LinkedHashMap(JDK 1.4):很像HashMap,但是用Iterator進行遍歷的時候,它會按插入順序或最先使用的順序(least-recently-used (LRU)order)進行訪問。除了用Iterator外,其他情況下,只是比HashMap稍慢一點。用Iterator的情況下,由於是使用鏈表來保存內部順序,因此速度會更快。
TreeMap:基於紅黑樹數據結構的實現。當你查看鍵或pair時,會發現它們時按順序(根據Comparable或Comparator,我們過一會講)排列的。TreeMap的特點時,你鎖得到的時一個有序的Map。TreeMap是Map中唯一有subMap()方法的實現。這個方法能讓你獲取這個樹中的一部分。
WeakHashMap:一個weak key的Map,是爲某些特殊問題而設計的。它能讓Map釋放其所持有的對象。如果某個對象除了在Map當中充當鍵之外,在其他地方都沒有其reference的話,那它將被當作垃圾回收。
IdentityHashMap(JDK 1.4):一個用==,而不是equals()來比較鍵的hash map。不是爲我們平常使用而設計的,是用來解決特殊問題的。
散列是往Map裏存數據的常用算法。

 

SortedMap
SortedMap(只有TreeMap這一個實現)的鍵肯定是有序的,因此這個接口裏面就有一些附加功能的方法了。
Comparator comparator():返回Map所使用的comparator,如果是用Object內置的方法的話,則返回null。
Object firstKey():返回第一個鍵。
Object lastKey():返回最後一個鍵。
SortedMap subMap(fromKey, toKey):返回這個Map的一個子集,其鍵從fromKey開始到toKey爲止,包括前者,不包括後者。
SortedMap headMap(toKey):返回這個Map的一愕嘎子集,其鍵均小於toKey。
SortedMap tailMap(fromKey):返回這個Map的一個子集,其鍵均大於等於fromKey。
pair是按key的順序存儲的,由於TreeMap有順序的概念,因此“位置”是有意義的,所以你可以去獲取它的第一個和最後一個元素,以及它的子集。

 

LinkedHashMap
爲了提高速度,LinkedHashMap對所有東西都做了hash,而且遍歷的時候(println()會遍歷整個Map,所以你能看到這個過程)還會按插入順序返回pair。此外,你還可以在LinkedHashMap的構造函數裏面進行配置,讓它使用基於訪問的LRU(least-recently -used)算法,這樣還沒被訪問過的元素(同時也是要刪除的候選對象)就會出現在隊列的最前頭。這樣,爲節省資源而寫一個定時清理的程序就變得很簡單了。

 5.總結Java標準類庫的容器類:
1)數組把對象和數字形式的下標聯繫起來。它持有的是類型確定的對象,這樣提取對象的時候就不用再作類型傳遞了。它可以是多維的,也可以持有primitive。但是創建之後它的容量不能改了。
2)Collection持有單個元素,而Map持有相關聯的pair。
3)和數組一樣,List也把數字下標同對象聯繫起來,你可以把數組和List想成有序的容器。List會隨元素的增加自動調整容量。但是List只能持有Object reference,所以不能存放primitive,而且把Object提取出來之後,還要做類型傳遞。
4)如果要做很多隨機訪問,那麼請用ArrayList,但是如果要再List的中間做很多插入和刪除的話,就應該用LinkedList了。
5)LinkedList能提供隊列,雙向隊列和棧的功能。
6)Map提供的不是對象與數組的關聯,而是對象和對象的關聯。
HashMap看重的是訪問速度,而TreeMap各國那看重鍵的順序,因而它不如HashMap那麼快。而LinkedHashMap則保持對象插入的順序,但是也可以用LRU算法爲它重新排序。
7)Set只接受不重複的對象。HashSet提供了最快的查詢速度。而TreeSet則保持元素有序。LinkedHashSet保持元素的插入順序。
8)沒必要再在新代碼裏使用舊類庫留下來的Vector,Hashtable和Stack了。
容器類庫是你每天都會用到的工具,它能使程序更簡介,更強大並且更搞笑。

 6.理解hashCode()
如果你不覆寫鍵的hashCode()和equals()的話,散列數據結構(HashSet,HashMap,LinkedHashSet,或LinkedHashMap)就沒法正確地處理鍵。
散列的價值就在於速度:散列算法能很快地找出東西。
數組是最快的數據結構。

7.Collection 和 Map 的區別
容器內每個爲之所存儲的元素個數不同。
Collection類型者,每個位置只有一個元素。
Map類型者,持有 key-value pair,像個小型數據庫。

8. 其他特徵
* List,Set,Map將持有對象一律視爲Object型別。
* Collection、List、Set、Map都是接口,不能實例化。
   繼承自它們的 ArrayList, Vector, HashTable, HashMap是具象class,這些纔可被實例化。
* vector容器確切知道它所持有的對象隸屬什麼型別。vector不進行邊界檢查。

9. 容器類和Array的區別、擇取
   * 容器類僅能持有對象引用(指向對象的指針),而不是將對象信息copy一份至數列某位置。
   * 一旦將對象置入容器內,便損失了該對象的型別信息。

10. 、* 在各種Lists中,最好的做法是以ArrayList作爲缺省選擇。當插入、刪除頻繁時,使用LinkedList();Vector總是比ArrayList慢,所以要儘量避免使用。
   * 在各種Sets中,HashSet通常優於HashTree(插入、查找)。只有當需要產生一個經過排序的序列,才用TreeSet。
     HashTree存在的唯一理由:能夠維護其內元素的排序狀態。
* 在各種Maps中:HashMap用於快速查找。
* 當元素個數固定,用Array,因爲Array效率是最高的。
結論:最常用的是ArrayList,HashSet,HashMap,Array。

11. 注意:
1)Collection沒有get()方法來取得某個元素。只能通過iterator()遍歷元素。
2)Set和Collection擁有一模一樣的接口。
3)List,可以通過get()方法來一次取出一個元素。使用數字來選擇一堆對象中的一個,get(0)...。(add/get)
4)一般使用ArrayList。用LinkedList構造堆棧stack、隊列queue。
5)Map用 put(k,v) / get(k),還可以使用containsKey()/containsValue()來檢查其中是否含有某個key/value。
   HashMap會利用對象的hashCode來快速找到key。
    * hashing
       哈希碼就是將對象的信息經過一些轉變形成一個獨一無二的int值,這個值存儲在一個array中。
       我們都知道所有存儲結構中,array查找速度是最快的。所以,可以加速查找。 發生碰撞時,讓array指向多個values。即,數組每個位置上又生成一個槤表。
6)Map中元素,可以將key序列、value序列單獨抽取出來。
使用keySet()抽取key序列,將map中的所有keys生成一個Set。
使用values()抽取value序列,將map中的所有values生成一個Collection。
爲什麼一個生成Set,一個生成Collection?那是因爲,key總是獨一無二的,value允許重複。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章