collection和map集合類知識點總結


collection和map集合類知識點總結

  

  最近在准備java基礎知識的總結,發現對於集合類的知識點很多很雜,借鑒網上的帖子,整理如下。

一、定義

    集合框架是為表示和操作集合而規定的一種統一的標准的體系結構,在java中的集合框架主要分為兩部分:Collection接口和Map接口。

二、  用法

(一)集合框架涉及的數據結構

    1.數據結構分類

    1)線性表是在內存中數據的一種組織、存儲的方式;一維數組、順序表、鏈表、棧、隊列,循環隊列、散列表等結構是邏輯上的概念,是一種理念與思想,是屬於線性表中的一種邏輯實現。

      2)Java中數據結構涉及到了數組(一維、多維)、順序表(ArrayList、Vector)、鏈表(LinkedArrayList、LinkedSet)、棧(stack)、隊列(Queue)、散列表(HashMap)、樹(TreeSet、TreeMap)等

(二)集合框架圖譜

    1.集合框架主要實現類

   

    2.集合框架類圖

    

    1)Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行,一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。

     2)所有實現Collection接口的類都必須提供兩個標准的構造函數:無參數的構造函數用於創建一個空的Collection,有一個Collection參數的構造函數用於創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后一個構造函數允許用戶復制一個Collection。

     3)為什么繼承Iterable接口而不繼承Iterator?

     因為Iterator接口的核心方法next()或者hasNext()是依賴於迭代器的當前迭代位置的。 如果Collection直接實現Iterator接口,勢必導致集合對象中包含當前迭代位置的數據(指針),當集合在不同方法間被傳遞時,由於當前迭代位置不可預置,那么next()方法的結果會變成不可預知。 除非再為Iterator接口添加一個reset()方法,用來重置當前迭代位置。 但即使這樣,Collection也只能同時存在一個當前迭代位置,而Iterable則不然,每次調用都會返回一個從頭開始計數的迭代器。 多個迭代器是互不干擾的。

     不同的Collection接口的子接口的實現類返回的Iterator具體類型可能不同,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,但是它們都實現了Iterator接口。因此,客戶端不關心到底是哪種 Iterator,它只需要獲得這個Iterator接口即可,這就是面向對象的威力。     

 

(三)Collection接口

    1.List接口

      List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似於數組下標)來訪問List中的元素,這類似於Java的數組。和下面要提到的Set不同,List允許有相同的元素。除了具Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標准的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。

      1)ArrayList

      ArrayList實現了可變大小的數組,它允許所有元素,包括null。size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間,其他的方法運行時間為線性。

       每個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小,這個容量可隨着不斷添加新元素而自動增加,但是增長算法並沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

 

      2)LinkedList

      LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque),可以認為LinkedList在方法和邏輯上和ArrayList是一樣的,只是在性能上有一定的區別,ArrayList適合隨機訪問LinkedList更適合插入和刪除,在對性能沒有很大要求是是可以忽略這個差別的。

     注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:

      List list = Collections.synchronizedList(new LinkedList(...));

 

      3)Vector

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

      ArrayList 和Vector是采用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要設計到數組元素移動等內存操作,所以索引數據快插入數據慢,Vector由於使用了synchronized方法(線程安全)所以性能上比ArrayList要差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向后遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入數度較快!

 

      4)Stack

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

 

     2.Set接口

     Set是一種不包括重復元素的Collection。它維持它自己的內部排序,所以隨機訪問沒有任何意義。與List一樣,它同樣運行null的存在但是僅有一個。由於Set接口的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變對象,如果在對集合中元素進行操作時,導致e1.equals(e2)==true,則必定會產生某些問題。實現了Set接口的集合有:EnumSet、HashSet、TreeSet。

      1)HashSet

      HashSet堪稱查詢速度最快的集合,因為其內部是以HashCode來實現的。它內部元素的順序是由哈希碼來決定的,所以它不保證set 的迭代順序,特別是它不保證該順序恆久不變。

 

      2)TreeSet

      基於TreeMap,生成一個總是處於排序狀態的set,內部以TreeMap來實現。它是使用元素的自然順序對元素進行排序,或者根據創建Set 時提供的Comparator進行排序,具體取決於使用的構造方法。

 

      3)LinkedHashSet

      底層是鏈表實現的,是set集合中唯一一個能保證怎么存就怎么取的集合對象,因為是HashSet的子類,所以也是保證元素唯一的,與HashSet的原理一樣。

 

    3.Queue接口

     1)阻塞式隊列(BlockingQueue):隊列滿了以后再插入元素則會拋出異常,主要包括ArrayBlockQueue、PriorityBlockingQueue、LinkedBlockingQueue。

       2)雙端隊列(Deque):支持在頭、尾兩端插入和移除元素,主要包括:ArrayDeque、LinkedBlockingDeque、LinkedList。

 

(四)Map接口

   Map與List、Set接口不同,它是由一系列鍵值對組成的集合,提供了key到Value的映射。同時它也沒有繼承Collection。在Map中它保證了key與value之間的一一對應關系。也就是說一個key對應一個value,所以它不能存在相同的key值,當然value值可以相同。實現map的有:HashMap、TreeMap、Hashtable、Properties、EnumMap。

 

      1)HashMap

      HashMap和Hashtable類似,不同之處在於HashMap是非同步的,並且允許null,即null value和null key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。

 

      2)TreeMap

      鍵以某種排序規則排序,內部以red-black(紅-黑)樹數據結構實現,實現了SortedMap接口

 

      3)Hashtable

     Hashtable繼承Dictionary類實現Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。添加數據使用put(key,value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。

        Hashtable通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。Hashtable是同步的。

 

三、總結

(一)集合類型的異同點

    1.Vector和ArrayList

      1)vector是線程同步的,所以它也是線程安全的,而arraylist是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用arraylist效率比較高。

       2)如果集合中的元素的數目大於目前集合數組的長度時,vector增長率為目前數組長度的100%,而arraylist增長率為目前數組長度的50%.如過在集合中使用數據量比較大的數據,用vector有一定的優勢。

       3)如果查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist都可以。而如果移動一個指定位置的數據花費的時間為0(n-i)n為總長度,這個時候就應該考慮到使用linklist,因為它移動一個指定位置的數據所花費的時間為0(1),而查詢一個指定位置的數據時花費的時間為0(i)。

      4)ArrayList 和Vector是采用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要設計到數組元素移動等內存操作,所以索引數據快插入數據慢,Vector由於使用了synchronized方法(線程安全)所以性能上比ArrayList要差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向后遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入數度較快!

 

     2.Aarraylist和Linkedlist

       1)ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。

         2)對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指針。

         3)對於新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。

         4)這一點要看實際情況的。若只對單條數據插入或刪除,ArrayList的速度反而優於LinkedList。但若是批量隨機的插入刪除數據,LinkedList的速度大大優於ArrayList. 因為ArrayList每插入一條數據,要移動插入點及之后的所有數據。

 

    3.HashMap與TreeMap

      1)HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該使用TreeMap(HashMap中元素的排列順序是不固定的)。HashMap中元素的排列順序是不固定的)。

       2)HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該使用TreeMap(HashMap中元素的排列順序是不固定的)。集合框架”提供兩種常規的Map實現:HashMap和TreeMap (TreeMap實現SortedMap接口)。

       3)在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現。 這個TreeMap沒有調優選項,因為該樹總處於平衡狀態。

 

    4.Hashtable與HashMap

      1)歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現 。

       2)同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 。

       3)值:只有HashMap可以讓你將空值作為一個表的條目的key或value 。

 

(二)如何選擇合適的集合類型

    1.對List的選擇

      1)對於隨機查詢與迭代遍歷操作,數組比所有的容器都要快。所以在隨機訪問中一般使用ArrayList。

       2)LinkedList使用雙向鏈表對元素的增加和刪除提供了非常好的支持,而ArrayList執行增加和刪除元素需要進行元素位移。

       3)對於Vector而已,我們一般都是避免使用。

       4)將ArrayList當做首選,畢竟對於集合元素而已我們都是進行遍歷,只有當程序的性能因為List的頻繁插入和刪除而降低時,再考慮LinkedList。

 

    2.對Set的選擇

      1)HashSet由於使用HashCode實現,所以在某種程度上來說它的性能永遠比TreeSet要好,尤其是進行增加和查找操作。

       2)雖然TreeSet沒有HashSet性能好,但是由於它可以維持元素的排序,所以它還是存在用武之地的。

 

    3.對Map的選擇

      1)HashMap與HashSet同樣,支持快速查詢。雖然HashTable速度的速度也不慢,但是在HashMap面前還是稍微慢了些,所以HashMap在查詢方面可以取代HashTable。

       2)由於TreeMap需要維持內部元素的順序,所以它通常要比HashMap和HashTable慢。

 


免責聲明!

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



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