Java容器類類庫的用途是“保存對象”,並將其划分為兩個不同的概念:
(1)Collection。一個獨立元素的序列,這些元素都服從一條或多條規則。List必須按照插入的順序保存元素,而Set不能有重復元素。Queue按照排隊規則來確定對象產生的順序。
(2)Map。一組成對的“鍵值對”對象,允許你使用鍵來查找值。映射表讓我們能夠使用一個對象來查找另一個對象,就像“字典”一樣。Map是強大的編程工具。
Map接口和Collection接口的不同
Map是雙列的,Collection是單列的
Map的鍵唯一,Collection的子體系Set是唯一的
Map集合的數據結構是針對鍵有效,跟值無關
Collection集合的數據結構是針對元素有效
一, Collection接口
(1). collection接口的成員方法
增加: boolean add(E e)
刪除: boolean remove(Object o)
清空: void clear()
包含: boolean contains(Object o)
判斷為空: boolean isEmpty()
容量: int size()
boolean addAll(Collection c)
boolean removeAll(Collection c)
boolean containsAll(Collection c)
boolean retainAll(Collection c)
(2). Object[] toArray()
把集合轉成數組,可以實現集合的遍歷.
(3). Iterator iterator()
迭代器,集合的專用遍歷方式.
使用方法iterator()要求容器返回一個Iterator
boolean hasNext() 檢查是否有下一個元素
E next() 獲取下一個元素
remove() 將迭代器新進返回的元素刪除
1, List接口(繼承Connection)
ArrayList(開發中用的很多)
底層數據結構是一個自增長的數組,查詢快,增刪慢.
線程不安全,效率高.
LinkedList
底層數據結構是鏈表(存儲地址不連續),查詢慢,增刪快
線程不安全,效率高
LinkedList類特有功能
public void addFirst(E e)及addLast(E e)
public E getFirst()及getLast()
public E removeFirst()及public E removeLast()
Vector
底層數據結構是也是數組,查詢快,增刪慢.
線程安全,效率低.
Vector類特有功能:
public void addElement(E obj)
public E elementAt(int index)
public Enumeration elements()
2, Set接口(繼承Connection)
Set是一個不包含重復元素的 collection。Set中最常被使用的是測試歸屬性,你可以很容易的查詢某個對象是否在其中。正因如此,查找成了set中的重要操作,因此你通常都會選擇一個HashSet實現,它專門進行了優化。
Set具有與Collection完全一樣的接口,因此沒有任何額外的功能,不像List一樣有不同的list。實際上Set就是Collection,只是行為不同。加入Set的元素必須定義equals方法以確保對象的唯一性
HashSet:為快速查找而設計的Set。存入HashSet的元素必須定義hashCode()方法,不保證set的迭代順序,特別是它不保證該順序恆久不變。
HashSet如何保證元素唯一性?底層數據結構是哈希表(元素是鏈表的數組)哈希表依賴於哈希值存儲添加功能底層依賴兩個方法: int hashCode()
boolean equals(Object obj)
LinkedHashSet:具有HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。於是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。元素也必須定義hashCode()方法
元素有序唯一
由鏈表保證元素有序
由哈希表保證元素唯一
TreeSet:保持次序的set,底層為樹結構。使用它可以從set中提取有序的序列。元素必須實現Comparable接口。
使用元素的自然順序對元素進行排序
或者根據創建 set 時提供的 Comparator 進行排序
具體取決於使用的構造方法。
必須提的一點:TreeSet是如何保證元素的排序和唯一性的?
底層數據結構是紅黑樹(紅黑樹是一種自平衡的二叉樹)!
各種set集合性能分析
HashSet和TreeSet是Set集合中用得最多的集合。HashSet總是比TreeSet集合性能好,因為HashSet不需要額外維護元素的順序。
LinkedHashSet需要用額外的鏈表維護元素的插入順序,因此在插入時性能比HashSet低,但在迭代訪問(遍歷)時性能更高。因為插入的時候即要計算hashCode又要維護鏈表,而遍歷的時候只需要按鏈表來訪問元素。
EnumSet元素是所有Set元素中性能最好的,但是它只能保存Enum類型的元素
3, Queue接口
Queue隊列,它主要分為兩大類,一類是阻塞式隊列,隊列滿了以后再插入元素則會拋出異常,主要包括ArrayBlockQueue、PriorityBlockingQueue、LinkedBlockingQueue。另一類則是雙端隊列,支持在頭、尾兩端插入和移除元素,主要包括:ArrayDeque、LinkedBlockingDeque、**LinkedList**。
1
Queue用於模擬隊列這種數據結構,隊列通常是指“先進先出”的容器。隊列的頭部保存在隊列中時間最長的元素,隊列的尾部 保存在隊列中時間最短的元素。新元素插入到隊列的尾部,訪問元素操作會返回隊列頭部的元素。通常,隊列不允許隨機訪問隊列中的元素。
Queue接口中定義了如下操作方法:
void add(Object e): 將指定元素加入此隊列的尾部。
Object element(): 獲取隊列頭部的元素,但是不刪除該元素。
boolean offer(Object e): 將指定元素加入此隊列的尾部。當使用有容量限制的隊列時,此方法通常比add(Object e)方法更好。
Object peek(): 獲取隊列頭部的元素,但是不刪除該元素。如果此隊列為空,則返回null。
Object poll(): 獲取隊列頭部的元素,並刪除該元素。如果此隊列為空,則返回null。
Object remove(): 獲取隊列頭部的元素,並刪除該元素。
Queue有兩個常用的實現類:LinkedList和PriorityQueue。
LinkedList類 是一個比較奇怪的類,它是List接口的實現類–這意味着它是一個List集合,可以根據索引來隨機訪問集合中的元素。除此之外,LinkedList還實現了Deque接口,Deque接口是Queue接口的子接口,它代表一個雙向隊列Deque接口里定義了一些可以雙向操作隊列的方法。
LinkedList與ArrayList的實現機制完全不同,ArrayList內部以數組的形式來保存集合中的元素,因此隨機訪問集合元素上有較好的性能;而LinkedList內部以鏈表的形式來保存集合中的元素,因此隨機訪問集合元素時性能較差,但在插入、刪除元素時性能非常出色(只需改變指針所指的地址即可)。
通常的編程過程中無須理會ArrayList和LinkedList之間的性能差異,只需知道LinkedList集合不僅提供了List的
功能,還額外提供了的雙向隊列、棧的功能。但在一些性能非常敏感的地方,可能需要慎重選擇哪個List實現。
4, Map接口(實現Connection)
Map的思想,映射表(也可以稱為關聯數組)的基本思想是它維護的鍵-值(對)關聯,因此你可以使用鍵來查找值。標准的Java類庫中包含了Map的集中基本實現類,包括HashMap,TreeMap、LinkedHashMap、WeakHashMap,ConcurrentHashMap、IdentityHashMap。它們都有同樣的基本接口Map,但是行為特效各不同,這表現在效率、鍵值對的保存及呈現次序、對象的保存周期、映射表如何在多線程程序中工作和判定“鍵”等價的策略等方面。Map接口實現的數量應該可以讓你感覺到這種工具的重要性。
1
Map接口成員方法:
V put(K key,V value)
V remove(Object key)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
V get(Object key)
Set keySet()
Collection values()
Set<Map.Entry<K,V>> entrySet()
這里提一下Map的遍歷方式吧:
方式1:根據鍵找值
獲取所有鍵的集合
遍歷鍵的集合,獲取到每一個鍵
根據鍵找值
方式2:根據鍵值對對象找鍵和值
獲取所有鍵值對對象的集合
遍歷鍵值對對象的集合,獲取到每一個鍵值對對象
根據鍵值對對象找鍵和值
1
2
3
HashMap:Map基於散列表的實現(它取代 了Hashtable)。插入和查詢“鍵值對”的開銷是固定的。可以通過構造器設置容器和負載因子,以調整容器的性能。
LinkedHashMap:類似於HashMap,但是迭代遍歷它時,取得“鍵值對”的順序是其插入次序,或者是最近最少使用的(LRU)的次序。只是比HashMap慢一點,而在迭代訪問時,反而更快,因為它使用鏈表維護內部次序。
TreeMap:基於紅黑樹的實現,查看“鍵”或“鍵值對”時,它們會被排序(次序由Comparable或Comparator決定)。TreeMap的特點在於所得到的結果是經過排序的。TreeMap是唯一帶有subMap()方法的Map,它可以返回一個子樹
WeakHashMap:弱鍵(weak key)映射,允許釋放映射所指向的對象,這是為解決某類特殊問題而設計的。如果映射之外沒有引用指向某個“鍵”,則此鍵可以被垃圾回收器回收。
ConcurrentHashMap:一種線程安全的Map,它不涉及加同步鎖。
IdentityHashMap:使用==代替equals()對“鍵”進行比較的散列映射。專為解決特殊問題而設計的。
既然談到了HashMap那么就來總結一下與Hashtable的不同,最直觀的方法,看其底層實現的源碼。
1.它們的家族就不同,雖然都實現了Map接口,但HashMap是繼承自AbstractMap,Hashtable繼承自古老的Dictionary
2.HashMap是允許key為null的,而Hashtbale是不允許的
3.在Hashtable的源碼里,一眼我們就能看到一個關鍵字 -----**synchronized ,**所以其是線程同步的,HashMap不是線程同步的,所以效率會高上一些,簡而言之,HashMap是Hashtable的輕量級實現(非線程安全實現)
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步(Collections.synchronizedMap)。
二、各種集合的異同點
1、Vector和ArrayList
1,vector是線程同步的,所以它也是線程安全的,而arraylist是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用arraylist效率比較高。
2,如果集合中的元素的數目大於目前集合數組的長度時,vector增長率為目前數組長度的100%,而arraylist增長率為目前數組長度的50%.如果在集合中使用數據量比較大的數據,用vector有一定的優勢。
3,如果查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist都可以。而如果移動一個指定位置的數據花費的時間為0(n-i)n為總長度,這個時候就應該考慮到使用arraylist,因為它移動一個指定位置的數據所花費的時間為0(1),而查詢一個指定位置的數據時花費的時間為0(i)。
ArrayList 和Vector是采用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要涉及到數組元素移動等內存操作,所以索引數據快插入數據慢,Vector由於使用了synchronized方法(線程安全)所以性能上比ArrayList要差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向后遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入數度較快!
1
2
3
4
5
2、Aarraylist和Linkedlist
1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
2.對於隨機訪問get和set,ArrayList絕對優於LinkedList,因為LinkedList要移動指針。
3.對於新增和刪除操作add和remove,LinkedList比較占優勢,因為ArrayList要移動數據。
1
2
3
這一點要看實際情況的。若只對單條數據插入或刪除,ArrayList的速度反而優於LinkedList。但若是批量隨機的插入刪除數據,LinkedList的速度大大優於ArrayList. 因為ArrayList每插入一條數據,要移動插入點及之后的所有數據。
3、HashMap與TreeMap
1、 HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該使用TreeMap(HashMap中元素的排列順序是不固定的)。集合框架”提供兩種常規的Map實現:HashMap和TreeMap (TreeMap實現SortedMap接口)。
2、在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現。 TreeMap沒有這個調優選項,因為該樹總處於平衡狀態。
1
2
3
4、hashtable與hashmap
1、歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現 。
2、同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 。
3、值:只有HashMap可以讓你將空值作為一個表的條目的key或value 。
1
2
3
4
5
三、對集合的選擇
1、對List的選擇
1、對於隨機查詢與迭代遍歷操作,數組比所有的容器都要快。所以在隨機訪問中一般使用ArrayList
2、LinkedList使用雙向鏈表對元素的增加和刪除提供了非常好的支持,而ArrayList執行增加和刪除元素需要進行元素位移。
3、對於Vector而言,我們一般都是避免使用。
4、將ArrayList當做首選,畢竟對於集合元素而已我們都是進行遍歷,只有當程序的性能因為List的頻繁插入和刪除而降低時,再考慮LinkedList。
1
2
3
4
5
6
7
2、對Set的選擇
1、HashSet由於使用HashCode實現,所以在某種程度上來說它的性能永遠比TreeSet要好,尤其是進行增加和查找操作。
3、雖然TreeSet沒有HashSet性能好,但是由於它可以維持元素的排序,所以它還是存在用武之地的。
1
2
3
3、對Map的選擇
1、HashMap與HashSet同樣,支持快速查詢。雖然HashTable速度的速度也不慢,但是在HashMap面前還是稍微慢了些,所以HashMap在查詢方面可以取代HashTable。
2、由於TreeMap需要維持內部元素的順序,所以它通常要比HashMap和HashT