Java集合全面解析

java集合的使用極其頻繁,文章將從總體上對集合進行描述,主要介紹集合分類、常見的集合、集合之間的區別等。

 

1 集合和數組的區別

(1)長度區別。數組長度不可變,集合長度可變。

(2)內容區別。數組可以存儲基本數據類型和對象引用,集合只能存儲對象引用。

(3)數組只能存儲同一類型的元素,集合可以存儲不同類型的元素。

 

2 Java集合體系間的繼承關係

Java 集合框架主要包括兩種類型的容器,一種是集合(Collection),存儲一個元素集合,另一種是圖(Map),存儲鍵/值對映射。

(1)Collection

繼承關係如下圖所示,常用的實現類有ArrayList,LinkedList,HashSet,LinkedHashSet。

Collection集合的方法如下圖所示:

(2)Map

Map保存的每項數據都是鍵值對(key-value),Map中的key是不可重複的,key用於標識集合裏的每項數據。

其中,HashMap和TreeMap是經常用到的實現類。

 

3.List和Set詳解

(1)List和Set的區別

 此外,

List和Set都繼承自Collection接口,Map則不是 。

Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。 
List:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因爲會引起其他元素位置改變。

(2)List

常用實現類:

(1)ArrayList:底層數據結構是數組,地址連續,查詢快,增刪慢,線程不安全,效率高,可以存儲重複元素 。
(2)LinkedList 底層數據結構是鏈表,地址不連續,查詢慢,增刪快,線程不安全,效率高,可以存儲重複元素 。
(3)Vector:底層數據結構是數組,查詢快,增刪慢,線程安全,效率低,可以存儲重複元素 。

List適用場景分析: 
當需要對數據進行多次訪問的情況下選用ArrayList,當需要對數據進行多次增加刪除修改時採用LinkedList。

ArrayList和Vector都是用數組實現的,主要有這麼三個區別: 
(1).Vector是多線程安全的,線程安全就是說多線程訪問同一代碼,不會產生不確定的結果。而ArrayList不是,這個可以從源碼中看出,Vector類中的方法很多有synchronized進行修飾,這樣就導致了Vector在效率上無法與ArrayList相比; 
(2)兩個都是採用的線性連續空間存儲元素,但是當空間不足的時候,兩個類的增加方式是不同。 
*(3)*Vector可以設置增長因子,而ArrayList不可以。 
*(4)*Vector是一種老的動態數組,是線程同步的,效率很低,一般不贊成使用。


(3)Set

 3.1 HashSet底層數據結構採用哈希表實現,元素無序且唯一,線程不安全,效率高,可以存儲null元素,元素的唯一性是靠所存儲元素類型是否重寫hashCode()和equals()方法來保證的,如果沒有重寫這兩個方法,則無法保證元素的唯一性。 

具體實現唯一性的比較過程:存儲元素首先會使用hash()算法函數生成一個int類型hashCode散列值,然後已經的所存儲的元素的hashCode值比較,如果hashCode不相等,則所存儲的兩個對象一定不相等,此時存儲當前的新的hashCode值處的元素對象;如果hashCode相等,存儲元素的對象還是不一定相等,此時會調用equals()方法判斷兩個對象的內容是否相等,如果內容相等,那麼就是同一個對象,無需存儲;如果比較的內容不相等,那麼就是不同的對象,就該存儲了,此時就要採用哈希的解決地址衝突算法,在當前hashCode值處類似一個新的鏈表, 在同一個hashCode值的後面存儲存儲不同的對象,這樣就保證了元素的唯一性。 
Set的實現類的集合對象中不能夠有重複元素,HashSet也一樣他是使用了一種標識來確定元素的不重複,HashSet用一種算法來保證HashSet中的元素是不重複的, HashSet採用哈希算法,底層用數組存儲數據。默認初始化容量16,加載因子0.75。 
Object類中的hashCode()的方法是所有子類都會繼承這個方法,這個方法會用Hash算法算出一個Hash(哈希)碼值返回,HashSet會用Hash碼值去和數組長度取模, 模(這個模就是對象要存放在數組中的位置)相同時纔會判斷數組中的元素和要加入的對象的內容是否相同,如果不同纔會添加進去。 
Hash算法是一種散列算法。 
Set hs=new HashSet();

hs.add(o); 

o.hashCode(); 

o%當前總容量 (0–15) 

| 不發生衝突 
是否發生衝突—————–直接存放 

| 發生衝突 
| 假(不相等) 
o1.equals(o2)——————-找一個空位添加 

| 是(相等) 
不添加 
覆蓋hashCode()方法的原則: 
1、一定要讓那些我們認爲相同的對象返回相同的hashCode值 
2、儘量讓那些我們認爲不同的對象返回不同的hashCode值,否則,就會增加衝突的概率。 
3、儘量的讓hashCode值散列開(兩值用異或運算可使結果的範圍更廣) 
HashSet 的實現比較簡單,相關HashSet的操作,基本上都是直接調用底層HashMap的相關方法來完成,我們應該爲保存到HashSet中的對象覆蓋hashCode()和equals(),因爲再將對象加入到HashSet中時,會首先調用hashCode方法計算出對象的hash值,接着根據此hash值調用HashMap中的hash方法,得到的值& (length-1)得到該對象在hashMap的transient Entry[] table中的保存位置的索引,接着找到數組中該索引位置保存的對象,並調用equals方法比較這兩個對象是否相等,如果相等則不添加,注意:所以要存入HashSet的集合對象中的自定義類必須覆蓋hashCode(),equals()兩個方法,才能保證集合中元素不重複。在覆蓋equals()和hashCode()方法時, 要使相同對象的hashCode()方法返回相同值,覆蓋equals()方法再判斷其內容。爲了保證效率,所以在覆蓋hashCode()方法時, 也要儘量使不同對象儘量返回不同的Hash碼值。

如果數組中的元素和要加入的對象的hashCode()返回了相同的Hash值(相同對象),纔會用equals()方法來判斷兩個對象的內容是否相同。
3.2 LinkedHashSet底層數據結構採用鏈表和哈希表共同實現,鏈表保證了元素的順序與存儲順序一致,哈希表保證了元素的唯一性。線程不安全,效率高。 

3.3 TreeSet底層數據結構採用二叉樹來實現,元素唯一且已經排好序;唯一性同樣需要重寫hashCode和equals()方法,二叉樹結構保證了元素的有序性。根據構造方法不同,分爲自然排序(無參構造)和比較器排序(有參構造),自然排序要求元素必須實現Compareable接口,並重寫裏面的compareTo()方法,元素通過比較返回的int值來判斷排序序列,返回0說明兩個對象相同,不需要存儲;比較器排需要在TreeSet初始化是時候傳入一個實現Comparator接口的比較器對象,或者採用匿名內部類的方式new一個Comparator對象,重寫裏面的compare()方法。

set適用場景分析

HashSet是基於Hash算法實現的,其性能通常都優於TreeSet。爲快速查找而設計的Set,我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet。 

 

4 Map詳解

Map 沒有繼承 Collection 接口, Map 提供 key 到 value 的映射,你可以通過“鍵”查找“值”。一個 Map 中不能包含相同的 key ,每個 key 只能映射一個 value 。 Map 接口提供 3 種集合的視圖, Map 的內容可以被當作一組 key 集合,一組 value 集合,或者一組 key-value 映射。 
(1)Map的主要方法

 

 (2)HashMap和HashTable的比較

(2)TreeMap:

 

適用場景分析: 
HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。

HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允許空鍵值,而HashTable不允許。

HashMap:適用於Map中插入、刪除和定位元素。 
Treemap:適用於按自然順序或自定義順序遍歷鍵(key)。

5.線程安全集合類與非線程安全集合類 LinkedList、ArrayList、HashSet是非線程安全的,Vector是線程安全的; 
HashMap是非線程安全的,HashTable是線程安全的; 
StringBuilder是非線程安全的,StringBuffer是線程安全的。

 

參考書目及博客:略。

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