提到集合以前,先說說數組Array和集合的區別:
html
(1)數組是大小固定的,而且同一個數組只能存放類型同樣的數據(基本類型/引用類型)
java
(2)JAVA集合能夠存儲和操做數目不固定的一組數據。
程序員
(3)若程序時不知道究竟須要多少對象,須要在空間不足時自動擴增容量,則須要使用容器類庫,array不適用。
算法
FYI:使用相應的toArray()和Arrays.asList()方法能夠相互轉換。
api
1、集合數組
集合類存放於java.util包中。
集合類存放的都是對象的引用,而非對象自己,出於表達上的便利,咱們稱集合中的對象就是指集合中對象的引用(reference)。
集合類型主要有3種:set(集)、list(列表)和map(映射)。安全
1、這三者什麼關係呢數據結構
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap併發
1.Collection接口
Collection是最基本的集合接口,一個Collection表明一組Object,即Collection的元素(Elements)。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的「子接口」如List和Set。
全部實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用於建立一個空的Collection,有一個 Collection參數的構造函數用於建立一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。後一個構造函數容許用戶複製一個Collection。
如何遍歷Collection中的每個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子便可逐一訪問Collection中每個元素。典型的用法以下:app
Iterator it = collection.iterator(); // 得到一個迭代子 while(it.hasNext()) { Object obj = it.next(); // 獲得下一個元素 }
iterator接口:
由Collection接口派生的兩個接口是List和Set。
2.Set
Set接口一樣是Collection接口的一個子接口,它表示數學意義上的集合概念。Set中不包含重複的元素,即Set中不存兩個這樣的元素e1和e2,使得e1.equals(e2)爲true。因爲Set接口提供的數據結構是數學意義上集合概念的抽象,所以它須要支持對象的添加、刪除,而不需提供隨機訪問。故Set接口與Collection的接口相同。
Set
接口繼承Collection
接口,並且它不容許集合中存在重複項。全部原始方法都是現成的,沒有引入新方法。具體的Set
實現類依賴添加的對象的equals()
方法來檢查等同性。
HashSet: 使用HashMap的一個集的實現。雖然集定義成無序,但必須存在某種方法能至關高效地找到一個對象。使用一個HashMap對象實現集的存儲和檢索操做是在固定時間內實現的.
TreeSet: 在集中以升序對對象排序的集的實現。這意味着從一個TreeSet對象得到第一個迭代器將按升序提供對象。TreeSet類使用了一個TreeMap.
爲優化 HashSet
空間的使用,您能夠調優初始容量和負載因子。TreeSet
不包含調優選項,由於樹老是平衡的,保證了插入、刪除、查詢的性能爲log(n)
。
HashSet
和 TreeSet
都實現 Cloneable
接口。
當您要從集合中以有序的方式抽取元素時,TreeSet
實現會有用處。爲了能順利進行,添加到TreeSet
的元素必須是可排序的。 Set的演示:
import java.util.*; public class SetExample { public static void main(String args[]) { Set set = new HashSet(); set.add("Bernadine"); set.add("Elizabeth"); set.add("Gene"); set.add("Elizabeth"); set.add("Clara"); System.out.println(set); Set sortedSet = new TreeSet(set); System.out.println(sortedSet); } }
運行程序產生了如下輸出。請注意重複的條目只出現了一次,列表的第二次輸出已按字母順序排序。
[Gene, Clara, Bernadine, Elizabeth] [Bernadine, Clara, Elizabeth, Gene]
3.List
List
接口繼承了Collection
接口以定義一個容許重複項的有序集合。該接口不但可以對列表的一部分進行處理,還添加了面向位置的操做。
實際上有兩種List: 一種是基本的ArrayList,其優勢在於隨機訪問元素,另外一種是更強大的LinkedList,它並非爲快速隨機訪問設計的,而是具備一套更通用的方法。
List : 次序是List最重要的特色:它保證維護元素特定的順序。List爲Collection添加了許多方法,使得可以向List中間插入與移除元素(這隻推薦LinkedList使用。)一個List能夠生成ListIterator,使用它能夠從兩個方向遍歷List,也能夠從List中間插入和移除元素。 ArrayList : 由數組實現的List。容許對元素進行快速隨機訪問,可是向List中間插入與移除元素的速度很慢。ListIterator只應該用來由後向前遍歷ArrayList,而不是用來插入和移除元素。由於那比LinkedList開銷要大不少。
LinkedList : 對順序訪問進行了優化,向List中間插入與刪除的開銷並不大,隨機訪問則相對較慢。(使用ArrayList代替。)還具備下列方法:addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 這些方法 (沒有在任何接口或基類中定義過)使得LinkedList能夠看成堆棧、隊列和雙向隊列使用。
Vector:實現一個相似數組同樣的表,自動增長容量來容納你所需的元素。使用下標存儲和檢索對象就象在一個標準的數組中同樣。你也能夠用一個迭代器從一個Vector中檢索對象。Vector是惟一的同步容器類!!當兩個或多個線程同時訪問時也是性能良好的。
Stsck: 這個類從Vector派生而來,而且增長了方法實現棧!一種後進先出的存儲結構。
面向位置的操做包括插入某個元素或 Collection
的功能,還包括獲取、除去或更改元素的功能。在 List
中搜索元素能夠從列表的頭部或尾部開始,若是找到元素,還將報告元素所在的位置。
void add(int index, Object element) boolean addAll(int index, Collection collection) Object get(int index) int indexOf(Object element) int lastIndexOf(Object element) Object remove(int index) Object set(int index, Object element)
接口不但以位置友好的方式遍歷整個列表,還能處理集合的子集: List
ListIterator listIterator() ListIterator listIterator(int startIndex) List subList(int fromIndex, int toIndex)
處理subList()
時,位於fromIndex
的元素在子列表中,而位於toIndex
的元素則不是,提醒這一點很重要。如下for-loop
測試案例大體反映了這一點:
for (int i=fromIndex; i<toIndex; i++) { // process element at position i }
List用法示例:
其中set方法返回的是被替換的內容。
4.List和Set對比
Linked 改快讀慢
Array 讀快改慢
Hash 兩都之間
Collection是集合接口
|————Set子接口:無序,不容許重複。
|————List子接口:有序,能夠有重複元素。
區別:Collections是集合類
Set和List對比:
Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引發元素位置改變。
List:和數組相似,List能夠動態增加,查找元素效率高,插入刪除元素效率低,由於會引發其餘元素位置改變。
Set和List具體子類:
Set
|————HashSet:以哈希表的形式存放元素,插入刪除速度很快。
List
|————ArrayList:動態數組
|————LinkedList:鏈表、隊列、堆棧。
Array和java.util.Vector
Vector是一種老的動態數組,是線程同步的,效率很低,通常不同意使用。
5.Map
Map
接口不是Collection
接口的繼承。而是從本身的用於維護鍵-值關聯的接口層次結構入手。按定義,該接口描述了從不重複的鍵到值的映射。
咱們能夠把這個接口方法分紅三組操做:改變、查詢和提供可選視圖。
改變操做容許您從映射中添加和除去鍵-值對。鍵和值均可覺得null
。可是,您不能把Map
做爲一個鍵或值添加給自身。
Object put(Object key, Object value)返回值是被替換的值。 Object remove(Object key) void putAll(Map mapping) void clear()
查詢操做容許您檢查映射內容:
Object get(Object key) boolean containsKey(Object key) boolean containsValue(Object value) int size() boolean isEmpty()
提供可選視圖方法容許您把鍵或值的組做爲集合來處理。
public Set keySet() public Collection values() public Set entrySet()
由於映射中鍵的集合必須是惟一的,您用Set
支持。由於映射中值的集合可能不惟一,您用Collection
支持。最後一個方法返回一個實現Map.Entry
接口的元素Set
。
Map.Entry 接口
Map
的entrySet()
方法返回一個實現Map.Entry
接口的對象集合。集合中每一個對象都是底層Map
中一個特定的鍵-值對。
經過這個集合迭代,您能夠得到每一條目的鍵或值並對值進行更改。可是,若是底層Map
在Map.Entry
接口的setValue()
方法外部被修改,此條目集就會變得無效,並致使迭代器行爲未定義。
HashMap 類和 TreeMap 類
「集合框架」提供兩種常規的Map
實現:HashMap
和TreeMap
。和全部的具體實現同樣,使用哪一種實現取決於您的特定須要。在Map
中插入、刪除和定位元素,HashMap
是最好的選擇。但若是您要按順序遍歷鍵,那麼TreeMap
會更好。根據集合大小,先把元素添加到HashMap
,再把這種映射轉換成一個用於有序鍵遍歷的TreeMap
可能更快。使用HashMap
要求添加的鍵類明肯定義了hashCode()
實現。有了TreeMap
實現,添加到映射的元素必定是可排序的。
爲了優化HashMap
空間的使用,您能夠調優初始容量和負載因子。這個TreeMap
沒有調優選項,由於該樹總處於平衡狀態。
HashMap
和TreeMap
都實現Cloneable
接口。
Hashtable
類和Properties
類是Map
接口的歷史實現。
HashTable: 實現一個映象,全部的鍵必須非空。爲了能高效的工做,定義鍵的類必須實現hashcode()方法和equal()方法。這個類是前面java實現的一個繼承,而且一般能在實現映象的其餘類中更好的使用。
HashMap: 實現一個映象,容許存儲空對象,並且容許鍵是空(因爲鍵必須是惟一的,固然只能有一個)。
WeakHashMap: 實現這樣一個映象:一般若是一個鍵對一個對象而言再也不被引用,鍵/對象對將被捨棄。這與HashMap造成對照,映象中的鍵維持鍵/對象對的生命週期,儘管使用映象的程序再也不有對鍵的引用,而且所以不能檢索對象。
TreeMap: 實現這樣一個映象,對象是按鍵升序排列的。
映射的使用示例:
如下程序演示了具體Map
類的使用。該程序對自命令行傳遞的詞進行頻率計數。HashMap
起初用於數據存儲。後來,映射被轉換爲TreeMap
以顯示有序的鍵列列表。
import java.util.*; public class MapExample { public static void main(String args[]) { Map map = new HashMap(); Integer ONE = new Integer(1); for (int i=0, n=args.length; i<n; i++) { String key = args[i]; Integer frequency = (Integer)map.get(key); if (frequency == null) { frequency = ONE; } else { int value = frequency.intValue(); frequency = new Integer(value + 1); } map.put(key, frequency); } System.out.println(map); Map sortedMap = new TreeMap(map); System.out.println(sortedMap); } }
結果:
//無序輸出: {prescribed=1, a=1, time=2, any=1, no=1, shall=1, nor=1, peace=1, owner=1, soldier=1, to=1, the=2, law=1, but=1, manner=1, without=1, house=1, in=4, by=1, consent=1, war=1, quartered=1, be=2, of=3} //有序輸出: {a=1, any=1, be=2, but=1, by=1, consent=1, house=1, in=4, law=1, manner=1, no=1, nor=1, of=3, owner=1, peace=1, prescribed=1, quartered=1, shall=1, soldier=1, the=2, time=2, to=1, war=1, without=1}
解疑:
一、什麼是Iterator
一些集合類提供了內容遍歷的功能,經過java.util.Iterator接口。這些接口容許遍歷對象的集合。依次操做每一個元素對象。當使用 Iterators時,在得到Iterator的時候包含一個集合快照。一般在遍歷一個Iterator的時候不建議修改集合本省。
二、Iterator與ListIterator有什麼區別?
Iterator:只能正向遍歷集合,適用於獲取移除元素。ListIerator:繼承Iterator,能夠雙向列表的遍歷,一樣支持元素的修改。
三、什麼是HaspMap和Map?
Map是接口,Java 集合框架中一部分,用於存儲鍵值對,HashMap是用哈希算法實現Map的類。
四、HashMap與HashTable有什麼區別?對比Hashtable VS HashMap
二者都是用key-value方式獲取數據。Hashtable是原始集合類之一(也稱做遺留類)。HashMap做爲新集合框架的一部分在Java2的1.2版本中加入。它們之間有一下區別:
● HashMap和Hashtable大體是等同的,除了非同步和空值(HashMap容許null值做爲key和value,而Hashtable不能夠)。
● HashMap無法保證映射的順序一直不變,可是做爲HashMap的子類LinkedHashMap,若是想要預知的順序迭代(默認按照插入順序),你能夠很輕易的置換爲HashMap,若是使用Hashtable就沒那麼容易了。
● HashMap不是同步的,而Hashtable是同步的。
● 迭代HashMap採用快速失敗機制,而Hashtable不是,因此這是設計的考慮點。
五、在Hashtable上下文中同步是什麼意思?
同步意味着在一個時間點只能有一個線程能夠修改哈希表,任何線程在執行hashtable的更新操做前須要獲取對象鎖,其餘線程等待鎖的釋放。
六、什麼叫作快速失敗特性
從高級別層次來講快速失敗是一個系統或軟件對於其故障作出的響應。一個快速失敗系統設計用來即時報告可能會致使失敗的任何故障狀況,它一般用來中止正常的操做而不是嘗試繼續作可能有缺陷的工做。當有問題發生時,快速失敗系統即時可見地發錯錯誤告警。在Java中,快速失敗與iterators有關。若是一個iterator在集合對象上建立了,其它線程欲「結構化」的修改該集合對象,併發修改異常 (ConcurrentModificationException) 拋出。
七、怎樣使Hashmap同步?
HashMap能夠經過Map m = Collections.synchronizedMap(hashMap)來達到同步的效果。
八、何時使用Hashtable,何時使用HashMap
基本的不一樣點是Hashtable同步HashMap不是的,因此不管何時有多個線程訪問相同實例的可能時,就應該使用Hashtable,反之使用HashMap。非線程安全的數據結構能帶來更好的性能。
若是在未來有一種可能—你須要按順序得到鍵值對的方案時,HashMap是一個很好的選擇,由於有HashMap的一個子類 LinkedHashMap。因此若是你想可預測的按順序迭代(默認按插入的順序),你能夠很方便用LinkedHashMap替換HashMap。反觀要是使用的Hashtable就沒那麼簡單了。同時若是有多個線程訪問HashMap,Collections.synchronizedMap()能夠代替,總的來講HashMap更靈活。
九、爲何Vector類認爲是廢棄的或者是非官方地不推薦使用?或者說爲何咱們應該一直使用ArrayList而不是Vector
你應該使用ArrayList而不是Vector是由於默認狀況下你是非同步訪問的,Vector同步了每一個方法,你幾乎從不要那樣作,一般有想要同步的是整個操做序列。同步單個的操做也不安全(若是你迭代一個Vector,你仍是要加鎖,以免其它線程在同一時刻改變集合).並且效率更慢。固然一樣有鎖的開銷即便你不須要,這是個很糟糕的方法在默認狀況下同步訪問。你能夠一直使用Collections.sychronizedList來裝飾一個集合。
事實上Vector結合了「可變數組」的集合和同步每一個操做的實現。這是另一個設計上的缺陷。Vector還有些遺留的方法在枚舉和元素獲取的方法,這些方法不一樣於List接口,若是這些方法在代碼中程序員更趨向於想用它。儘管枚舉速度更快,可是他們不能檢查若是集合在迭代的時候修改了,這樣將致使問題。儘管以上諸多緣由,Oracle也從沒宣稱過要廢棄Vector。
不少時候失敗了不是沒努力也不是運氣差,而是努力不夠,沒有推本身一把!