1. 程式人生 > 程式設計 >JAVA集合框架專題

JAVA集合框架專題

一、Java集合框架概述

JAVA集合框架專題

  集合可以看作是一種容器,用來儲存物件資訊。所有集合類都位於java.util包下,但支援多執行緒的集合類位於java.util.concurrent包下。

  陣列與集合的區別如下:

  (1)陣列長度不可變化而且無法儲存具有對映關係的資料;集合類用於儲存數量不確定的資料,以及儲存具有對映關係的資料。

  (2)陣列元素既可以是基本型別的值,也可以是物件;集合只能儲存物件。

  Java集合類主要由兩個根介面Collection和Map派生出來的,Collection派生出了三個子介面:List、Set、Queue(Java5新增的佇列),因此Java集合大致也可分成List、Set、Queue、Map四種介面體系,(注意:Map不是Collection的子介面)。

  其中List代表了有序可重複集合,可直接根據元素的索引來訪問;Set代表無序不可重複集合,只能根據元素本身來訪問;Queue是佇列集合;Map代表的是儲存key-value對的集合,可根據元素的key來訪問value。

  上圖中淡綠色背景覆蓋的是集合體系中常用的實現類,分別是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等實現類。

二、Java集合常見介面及實現類

1. Collection介面常見方法(來源於Java API)

2. Set集合

  Set集合與Collection的方法相同,由於Set集合不允許儲存相同的元素,所以如果把兩個相同元素新增到同一個Set集合,則新增操作失敗,新元素不會被加入,add()方法返回false。為了幫助理解,請看下面程式碼示例:

public class Test {

  public static void main(String[] args) {
    Set<String> set = new HashSet<String>();
    set.add("hello world");
    set.add("hello 冰湖一角");
    set.add("hello 冰湖一角");//新增不進去
    System.out.println("集合中元素個數:"+set.size());
    System.out.println("集合中元素為:"+set.toString());
  }
}

執行結果如下:

集合中元素個數:2
集合中元素為:[hello world,hello 冰湖一角]

分析:由於String類中重寫了hashCode()和equals()方法,用來比較指向的字串物件所儲存的字串是否相等。所以這裡的第二個"hello 冰湖一角"是加不進去的。

下面著重介紹Set集合幾個常用實現類:

(1)HashSet類

  HashSet是Set集合最常用實現類,是其經典實現。HashSet是按照hash演算法來儲存元素的,因此具有很好的存取和查詢效能。

  HashSet具有如下特點:

  • 不能保證元素的順序。
  • HashSet不是執行緒同步的,如果多執行緒操作HashSet集合,則應通過程式碼來保證其同步。
  • 集合元素值可以是null。

  HashSet儲存原理如下:

  當向HashSet集合儲存一個元素時,HashSet會呼叫該物件的hashCode()方法得到其hashCode值,然後根據hashCode值決定該物件的儲存位置。HashSet集合判斷兩個元素相等的標準是(1)兩個物件通過equals()方法比較返回true;(2)兩個物件的hashCode()方法返回值相等。因此,如果(1)和(2)有一個不滿足條件,則認為這兩個物件不相等,可以新增成功。如果兩個物件的hashCode()方法返回值相等,但是兩個物件通過equals()方法比較返回false,HashSet會以鏈式結構將兩個物件儲存在同一位置,這將導致效能下降,因此在編碼時應避免出現這種情況。

  HashSet查詢原理如下:

  基於HashSet以上的儲存原理,在查詢元素時,HashSet先計算元素的HashCode值(也就是呼叫物件的hashCode方法的返回值),然後直接到hashCode值對應的位置去取出元素即可,這就是HashSet速度很快的原因。

  重寫hashCode()方法的基本原則如下:

  • 在程式執行過程中,同一個物件的hashCode()方法返回值應相同。
  • 當兩個物件通過equals()方法比較返回true時,這兩個物件的hashCode()方法返回值應該相等。
  • 物件中用作equals()方法比較標準的例項變數,都應該用於計算hashCode值。

(2)LinkedHashSet類

  LinkedHashSet是HashSet的一個子類,具有HashSet的特性,也是根據元素的hashCode值來決定元素的儲存位置。但它使用連結串列維護元素的次序,元素的順序與新增順序一致。由於LinkedHashSet需要維護元素的插入順序,因此效能略低於HashSet,但在迭代訪問Set裡的全部元素時由很好的效能。

(3)TreeSet類

  TreeSet時SortedSet介面的實現類,TreeSet可以保證元素處於排序狀態,它採用紅黑樹的資料結構來儲存集合元素。TreeSet支援兩種排序方法:自然排序和定製排序,預設採用自然排序。

  • 自然排序

  TreeSet會呼叫集合元素的compareTo(Object obj)方法來比較元素的大小關係,然後將元素按照升序排列,這就是自然排序。如果試圖將一個物件新增到TreeSet集合中,則該物件必須實現Comparable介面,否則會丟擲異常。當一個物件呼叫方法與另一個物件比較時,例如obj1.compareTo(obj2),如果該方法返回0,則兩個物件相等;如果返回一個正數,則obj1大於obj2;如果返回一個負數,則obj1小於obj2。

  Java常用類中已經實現了Comparable介面的類有以下幾個:

  1. BigDecimal、BigDecimal以及所有數值型對應的包裝類:按照它們對應的數值大小進行比較。
  2. Charchter:按照字元的unicode值進行比較。
  3. Boolean:true對應的包裝類例項大於false對應的包裝類例項。
  4. String:按照字串中的字元的unicode值進行比較。
  5. Date、Time:後面的時間、日期比前面的時間、日期大。

  對於TreeSet集合而言,它判斷兩個物件是否相等的標準是:兩個物件通過compareTo(Object obj)方法比較是否返回0,如果返回0則相等。

  • 定製排序

  想要實現定製排序,需要在建立TreeSet集合物件時,提供一個Comparator物件與該TreeSet集合關聯,由Comparator物件負責集合元素的排序邏輯。

  綜上:自然排序實現的是Comparable介面,定製排序實現的是Comparator介面。(具體程式碼實現會在後續章節中講解)

(4)EnumSet類

  EnumSet是一個專為列舉類設計的集合類,不允許新增null值。EnumSet的集合元素也是有序的,它以列舉值在Enum類內的定義順序來決定集合元素的順序。

(5)各Set實現類的效能分析

  HashSet的效能比TreeSet的效能好(特別是新增,查詢元素時),因為TreeSet需要額外的紅黑樹演算法維護元素的次序,如果需要一個保持排序的Set時才用TreeSet,否則應該使用HashSet。

  LinkedHashSet是HashSet的子類,由於需要連結串列維護元素的順序,所以插入和刪除操作比HashSet要慢,但遍歷比HashSet快。

  EnumSet是所有Set實現類中效能最好的,但它只能 儲存同一個列舉類的列舉值作為集合元素。

  以上幾個Set實現類都是執行緒不安全的,如果多執行緒訪問,必須手動保證集合的同步性,這在後面的章節中會講到。

3. List集合

  List集合代表一個有序、可重複集合,集合中每個元素都有其對應的順序索引。List集合預設按照元素的新增順序設定元素的索引,可以通過索引(類似陣列的下標)來訪問指定位置的集合元素。

  實現List介面的集合主要有:ArrayList、LinkedList、Vector、Stack。

(1)ArrayList

ArrayList是一個動態陣列,也是我們最常用的集合,是List類的典型實現。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了陣列的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢位時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。

ArrayList擅長於隨機訪問。同時ArrayList是非同步的。

(2)LinkedList

LinkedList是List介面的另一個實現,除了可以根據索引訪問集合元素外,LinkedList還實現了Deque介面,可以當作雙端佇列來使用,也就是說,既可以當作“棧”使用,又可以當作佇列使用。

  LinkedList的實現機制與ArrayList的實現機制完全不同,ArrayLiat內部以陣列的形式儲存集合的元素,所以隨機訪問集合元素有較好的效能;LinkedList內部以連結串列的形式儲存集合中的元素,所以隨機訪問集合中的元素效能較差,但在插入刪除元素時有較好的效能。

(3)Vector

與ArrayList相似,但是Vector是同步的。所以說Vector是執行緒安全的動態陣列。它的操作與ArrayList幾乎一樣。

(4)Stack

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

(5)Iterator介面和ListIterator介面

  Iterator是一個介面,它是集合的迭代器。集合可以通過Iterator去遍歷集合中的元素。Iterator提供的API介面如下:

  • boolean hasNext():判斷集合裡是否存在下一個元素。如果有,hasNext()方法返回 true。
  • Object next():返回集合裡下一個元素。
  • void remove():刪除集合裡上一次next方法返回的元素。

  ListIterator介面繼承Iterator介面,提供了專門操作List的方法。ListIterator介面在Iterator介面的基礎上增加了以下幾個方法:

  • boolean hasPrevious():判斷集合裡是否存在上一個元素。如果有,該方法返回 true。
  • Object previous():返回集合裡上一個元素。
  • void add(Object o):在指定位置插入一個元素。

  以上兩個介面相比較,不難發現,ListIterator增加了向前迭代的功能(Iterator只能向後迭代),ListIterator還可以通過add()方法向List集合中新增元素(Iterator只能刪除元素)。

4. Map集合

  Map介面採用鍵值對Map<K,V>的儲存方式,儲存具有對映關係的資料,因此,Map集合裡儲存兩組值,一組值用於儲存Map裡的key,另外一組值用於儲存Map裡的value,key和value可以是任意引用型別的資料。key值不允許重複,可以為null。如果新增key-value對時Map中已經有重複的key,則新新增的value會覆蓋該key原來對應的value。常用實現類有HashMap、LinkedHashMap、TreeMap等。

  Map常見方法(來源於API)如下:

(1)HashMap與Hashtable

  HashMap與Hashtable是Map介面的兩個典型實現,它們之間的關係完全類似於ArrayList與Vertor。HashTable是一個古老的Map實現類,它提供的方法比較繁瑣,目前基本不用了,HashMap與Hashtable主要存在以下兩個典型區別:

  • HashMap是執行緒不安全,HashTable是執行緒安全的。
  • HashMap可以使用null值最為key或value;Hashtable不允許使用null值作為key和value,如果把null放進HashTable中,將會發生空指標異常。

  為了成功的在HashMap和Hashtable中儲存和獲取物件,用作key的物件必須實現hashCode()方法和equals()方法。

  HashMap工作原理如下:

  HashMap基於hashing原理,通過put()和get()方法儲存和獲取物件。當我們將鍵值對傳遞給put()方法時,它呼叫建物件的hashCode()方法來計算hashCode值,然後找到bucket位置來儲存值物件。當獲取物件時,通過建物件的equals()方法找到正確的鍵值對,然後返回物件。HashMap使用連結串列來解決碰撞問題,當發生碰撞了,物件將會儲存在連結串列的下一個節點中。

(2)LinkedHashMap實現類

  LinkedHashMap使用雙向連結串列來維護key-value對的次序(其實只需要考慮key的次序即可),該連結串列負責維護Map的迭代順序,與插入順序一致,因此效能比HashMap低,但在迭代訪問Map裡的全部元素時有較好的效能。

(3)Properties

  Properties類時Hashtable類的子類,它相當於一個key、value都是String型別的Map,主要用於讀取配置檔案。

(4)TreeMap實現類

  TreeMap是SortedMap的實現類,是一個紅黑樹的資料結構,每個key-value對作為紅黑樹的一個節點。TreeMap儲存key-value對時,需要根據key對節點進行排序。TreeMap也有兩種排序方式:

  • 自然排序:TreeMap的所有key必須實現Comparable介面,而且所有的key應該是同一個類的物件,否則會丟擲ClassCastException。
  • 定製排序:建立TreeMap時,傳入一個Comparator物件,該物件負責對TreeMap中的所有key進行排序。

(5)各Map實現類的效能分析

  • HashMap通常比Hashtable(古老的執行緒安全的集合)要快
  • TreeMap通常比HashMap、Hashtable要慢,因為TreeMap底層採用紅黑樹來管理key-value。
  • LinkedHashMap比HashMap慢一點,因為它需要維護連結串列來爆出key-value的插入順序。

以上就是JAVA集合框架專題的詳細內容,更多關於JAVA集合框架的資料請關注我們其它相關文章!