Java 集合(一)集合使用詳解

  在使用Java語言開發時,繞不開對集合的使用,因此,對集合的掌握是非常有必要的。除此之外,Java的集合框架設計也能看出一些數據結構的設計思想,對開發的進階是很有幫忙的。本系列文章以JDK1.6爲例,介紹下集合框架。

一、集合框架概述

  談Java集合框架,基本上繞不開一張圖,如下:

  從上圖可以看出,Java 集合框架主要包括兩種類型的容器,一種是Collection,存儲元素集合;另一種是Map,存儲鍵/值對映射。Collection 接口又有 3 種子類型,List、Set 和 Queue,再下面是一些抽象類,最後是具體實現類,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等。
  將這些子接口或實現類用一個簡單的圖來表示,如下:

二、Collection接口

2.1 List

  使用List存儲的特點:元素有序、可重複。常用的實現方式:ArrayList、Vector和LinkedList。

具體實現 優點 缺點
ArrayList 底層數據結構是數組,查詢快,效率高 增刪慢, 線程不安全
Vector 底層數據結構是數組,查詢快,線程安全 增刪慢,效率低
LinkedList 底層數據結構是鏈表,增刪快,效率高 查詢慢, 線程不安全

  ArrayList是一個動態數組,隨着容器中的元素不斷增加,容器的大小也會隨着增加。同時由於ArrayList底層是數組實現,所以可以隨機訪問元素。
  Vector與ArrayList類似,不過是同步的,因此Vector是線程安全的動態數組。此外, Stack繼承自Vector,實現一個後進先出的堆棧。
  LinkedList是一個雙向鏈表,LinkedList不能隨機訪問,增刪元素比較方便。

2.2 Set

  使用Set存儲的特點與List相反:元素無序、不可重複。常用的實現方式:HashSet、LinkedHashSet和TreeSet。

具體實現 優點 缺點
HashSet 底層數據結構是哈希表,可以存儲null元素,效率高 線程不安全,需要從重寫hashCode()和equals()來保證元素唯一性
LinkedHashSet 底層數據結構是鏈表和哈希表(鏈表保證了元素的順序與存儲順序一致,哈希表保證了元素的唯一性),效率高 線程不安全
TreeSet 底層數據結構是二叉樹,元素唯一且已經排好序 需要重寫hashCode和equals()來保證元素唯一性

  在使用Set存儲數據時,爲保障元素唯一性,常常要重寫hashCode。重寫hashCode方法時,儘量遵循以下原則:
   1>相同的對象返回相同的hashCode值
   2>不同的對象返回不同的hashCode值,否則,就會增加衝突的概率
   3>儘量的讓hashCode值散列開(用異或運算可使結果的範圍更廣)
  HashSet中沒有重複元素,底層由HashMap實現,不保證元素的順序(此處的沒有順序是指:元素插入的順序與輸出的順序不一致),HashSet允許使用null 元素,HashSet是非同步的。
  LinkedHashSet繼承自HashSet,其底層是基於LinkedHashMap來實現的,有序,非同步。
  TreeSet底層是基於TreeMap實現的,所以元素有序。TreeSet支持兩種排序方式,自然排序和定製排序,其中自然排序爲默認的排序方式。當我們構造TreeSet時,若使用不帶參數的構造函數,則TreeSet的使用自然比較器;若用戶需要使用自定義的比較器,則需要使用帶比較器的參數。TreeSet是非同步的。
  自然排序要求元素必須實現Compareable接口,並重寫裏面的compareTo()方法,元素通過比較返回的int值來判斷排序序列,返回0說明兩個對象相同;比較器排需要在TreeSet初始化是時候傳入一個實現Comparator接口的比較器對象,或者採用匿名內部類的方式new一個Comparator對象,重寫裏面的compare()方法。
  在使用Set存儲元素時,元素雖然無放入順序,但Set的底層實現其實是Map,元素在Set中的位置是有該元素的HashCode決定的,所以其位置其實是固定的。
  至於具體使用哪個集合時,參考如下:

  在List和Set兩個分支中,ArrayList和HashSet是對應分支中適應性最廣的,兩者再比較,ArrayList則適用性更廣一些。也就是說如果要確定用List,但不確定用哪種List,就可以使用ArrayList;如果確定用Set,但不確定用哪種Set,就可以使用HashSet。如果只知道用集合,就用ArrayList。

三、Map接口

  Map由一系列鍵值對組成的集合,提供了key到Value的映射。在Map中它保證了key與value之間的一一對應關係,即一個key對應一個value,所以不能存在相同的key值,value值可以相同。
  常用的Map有:HashMap、LinkedHashMap、TreeMap和HashTable。

具體實現 優點 缺點
HashMap 基於哈希表實現,查詢快,效率高 元素存儲時無序,非線程安全
LinkedHashMap 基於哈希表和鏈表實現,可以保留元素插入時的順序 非線程安全
TreeMap 存儲的元素有序 非線程安全
HashTable 線程安全,不允許null值 效率低

  至於具體使用哪個Map時,參考如下:

  在Map中,HashMap是對應分支中適應性最廣的。也就是說如果要確定用Map,但不確定用哪種Map,就可以使用HashMap。

四、集合的比較

4.1 ArrayList和LinkedList

   1>ArrayList基於動態數組,LinkedList基於鏈表。
   2>對於隨機訪問操作,ArrayList絕對優於LinkedList,因爲LinkedList要移動指針。
   3>對於增刪操作,LinedList比較佔優勢,因爲ArrayList要移動數據。

4.2 HashTable與HashMap

   1>同步性:HashTable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 。
   2>效率:HashTable效率最低,HashMap效率最高 。
   3>對null值的處理:HashMap的key、value都可爲null,HashTable的key、value都不可爲null 。
   4>支持的遍歷種類不同:HashMap只支持Iterator遍歷。而Hashtable支持Iterator和Enumeration兩種方式遍歷。

4.3 HashMap、Hashtable、LinkedHashMap和TreeMap

  HashMap根據鍵的HashCode 值存儲數據,具有很快的訪問速度。遍歷時,取得數據的順序是完全隨機的。HashMap最多隻允許一條記錄的鍵爲Null;允許多條記錄的值爲Null。
  HashMap不支持線程的同步,即任一時刻可以有多個線程同時寫HashMap;可能會導致數據的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力。
  Hashtable 與 HashMap類似,不同的是:它不允許記錄的鍵或者值爲空;它支持線程的同步,即任一時刻只有一個線程能寫Hashtable,因此也導致了Hashtale在寫入時會比較慢。
  LinkedHashMap保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時用帶參數,按照應用次數排序。
  TreeMap實現SortMap接口,內部實現是紅黑樹。能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時,得到的記錄是排過序的。TreeMap不允許key的值爲null。非同步的。

4.4 HashSet、LinkedHashSet、TreeSet

  當向HashSet結合中存入一個元素時,HashSet會調用該對象的hashCode()方法來得到該對象的hashCode值,然後根據 hashCode值來決定該對象在HashSet中存儲位置。簡單的說,HashSet集合判斷兩個元素相等的標準是兩個對象通過equals方法比較相等,並且兩個對象的hashCode()方法返回值也相等。
  LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的存儲位置,但是它同時使用鏈表維護元素的次序。這樣使得元素看起來像是以插入順序保存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的添加順序訪問集合的元素。
  LinkedHashSet在迭代訪問Set中的全部元素時,性能比HashSet好,但是插入時性能稍微遜色於HashSet。
  TreeSet是SortedSet接口的唯一實現類,TreeSet可以確保集合元素處於排序狀態。TreeSet支持兩種排序方式,自然排序和定製排序,其中自然排序爲默認的排序方式。向TreeSet中加入的應該是同一個類的對象。
TreeSet判斷兩個對象不相等的方式是兩個對象通過equals方法返回false,或者通過CompareTo方法比較沒有返回0。

4.5 從類名看特點

  Array***:底層數據結構是數組,查詢快,增刪慢。
  Linked***:底層數據結構是鏈表,查詢慢,增刪快。
  Hash***:底層數據結構是哈希表,元素相同與否取決於兩個方法:hashCode()和equals()。
  Tree***:底層數據結構是二叉樹,元素比較的兩種方式:自然排序和比較器排序。

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