## 集合框架

### List結構的集合類
### ArrayList類,LinkedList類,Vector類,Stack類
#### ArrayList集合類的使用方法(無同步性,線程不安全)
~~~
//ArrayList --- 實現了List接口,ArrayList是容量大小可變的數組的實現
ArrayList al = new ArrayList();
//將元素添加到al集合中的尾部
String str1 = "a";
al.add(str1);
String str2 = "b";
al.add(str2);
//將元素添加到al集合中的指定位置
String str3 = "c";
al.add(0, str3);
//可以添加重復元素
al.add(str1);
al.add(str2);
//按下標移除元素
al.remove(0);
//按元素移除集合中指定元素,PS:如果該元素在集合中不止一個,移除的元素是正序第一個匹配到的元素
al.remove(str2);
//遍歷輸出
for(int i = 0; i < al.size(); i++){
//按下標獲取元素,PS:因為get()方法返回的是Object類型的數據,所以要強制類型轉換
String tmp = (String)al.get(i);
System.out.print(tmp + " ");
}
System.out.println();
//擦除集合中所有元素
al.removeAll(al);
~~~
#### LinkedList集合類的使用方法
~~~
//LinkedList --- 實現的接口比較多,用的較多的是它的雙端隊列的特性
LinkedList ll = new LinkedList();
//上述ArrayList所使用的方法LinkedList都能使用
//除此之外,還有以下這些
//將元素添加到集合的首部
ll.addFirst(str1);
//將元素添加到集合的尾部
ll.addLast(str2);
ll.addLast(str3);
ll.addLast(str1);
ll.addLast(str2);
ll.addLast(str3);
ll.addLast(str1);
//移除集合首部元素
ll.removeFirst();
ll.remove();
//移除集合尾部元素
ll.removeLast();
//移除與指定元素相同的,從首部到尾部之間第一個元素
ll.removeFirstOccurrence(str1);
//移除與指定元素相同的,從首部到尾部之間最后一個元素
ll.removeLastOccurrence(str2);
//獲取首部元素
ll.getFirst();
//獲取尾部元素
ll.getLast();
//移除所有元素
ll.removeAll(ll);
~~~
#### Vector集合類的使用方法(線程安全具有同步性)
~~~
//Vector --- Vector可以實現可增長的對象數組,Vector的大小可以根據需要增大或縮小,以適應創建 Vector后進行添加或移除項的操作。
Vector v = new Vector();
//上述ArrayList所使用的方法Vector都能使用
//除此之外,還有以下這些
//添加一個組件到向量向量末尾
v.addElement(str1);
v.addElement(str2);
//返回向量當前的大小
v.capacity();
//判斷向量是否為空
v.isEmpty();
//獲取首部組件
v.firstElement();
//獲取尾部組件
v.lastElement();
//擴大該向量的大小
v.ensureCapacity(5);
//移除指定位置的組件
v.removeElementAt(0);
//移除正序第一個與指定組件相同的組件
v.removeElement(str1);
//移除所有組件,并將向量大小設置為0
v.removeAllElements();
~~~
#### Stack集合類(棧)的使用方法
~~~
//Stack --- Stack表示棧結構。繼承至 Vector。
//它提供了push和 pop操作,以及取堆棧頂點的 peek方法、測試棧是否為空的empty方法、在棧中查找項并確定到棧頂距離的search方法。
Stack s = new Stack();
//壓棧方法
s.push(str1);
s.push(str2);
s.push(str3);
//取棧頂元素方法
s.peek();
//出棧方法
s.pop();
//測試堆棧是否為空的方法
s.empty();
//在棧中查找項并確定到棧頂距離的方法,PS:返回值以1為棧頂基數,-1為未找到
System.out.println(s.search(str1));
~~~
#### ArrayList和Vector的區別
ArrayList與Vector都是java的集合類,都可以用來存放java對象,這是他們的相同點,但是他們也有區別:
1、同步性
????Vector是線程同步的。這個類中的一些方法保證了Vector中的對象是線程安全的。而ArrayList則是線程異步的,因此ArrayList中的對象并不是線程安全的。因為同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那么使用ArrayList是一個很好的選擇,這樣可以避免由于同步帶來的不必要的性能開銷。
2、數據增長
從內部實現機制來講ArrayList和Vector都是使用數組(Array)來控制集合中的對象。當你向這兩種類型中增加元素的時候,如果元素的數目超出了內部數組目前的長度它們都需要擴展內部數組的長度,Vector缺省情況下自動增長原來一倍的數組長度,ArrayList是原來的50%,所以最后你獲得的這個集合所占的空間總是比你實際需要的要大。所以如果你要在集合中保存大量的數據那么使用Vector有一些優勢,因為你可以通過設置集合的初始化大小來避免不必要的資源開銷。
### Map結構的集合類
### HashMap類,Hashtable類
#### HashMap集合類的使用方法
~~~
//Map結構常用的集合類
//HashMap --- 此實現假定哈希函數將元素適當地分布在各桶之間,其取出和存入的時間復雜度非常低,為常數級別,PS:不同存在相同鍵
HashMap hm = new HashMap();
//放入鍵值對
int num1 = 1;
hm.put(num1, str1);
//如果鍵以存在,則替換該鍵值對
hm.put(num1, str2);
int num2 = 2;
hm.put(num2, str2);
int num3 = 3;
hm.put(num3, str3);
//通過鍵獲取相應值
hm.get(num1);
//通過鍵判斷集合是否存在該鍵值對
hm.containsKey(num1);
//通過值判斷集合是否存在該鍵值對
hm.containsValue(str1);
//利用迭代器遍歷集合中的所有鍵值對
//keySet()返回此映射中所包含的鍵的Set視圖
//iterator()返回在此 set中的元素上進行迭代的迭代器
Iterator it = hm.keySet().iterator();
//hasNext()如果仍有元素可以迭代,則返回 true。
while(it.hasNext()){
//取出key
//next()返回迭代的下一個元素。
//toString()返回String類型數據,PS:這里不能強制類型轉換成String
int key = Integer.parseInt(it.next().toString());
//通過key獲取value
String tmp = (String)hm.get(key);
//輸出value
System.out.print(tmp + " ");
}
System.out.println();
~~~
#### Hashtable集合類的使用(Hashtable具有同步性,線程安全)
~~~
//HashTable --- Hashtable具有同步性,線程安全
//HashTable在用法上和HashMap基本相似
Hashtable ht = new Hashtable();
//放入空值會報錯
//ht.put(null, null);
//測試此哈希表是否沒有鍵映射到值。
ht.isEmpty();
~~~
#### HashMap和Hashtable集合類的區別
HashMap與Hashtable都是java的集合類,都可以用來存放java對象,這是他們的相同點,但是他們也有區別。
1、歷史原因
????Hashtable是基于陳舊的Dictionary類的,HashMap是java?1.2引進的Map接口的一個實現。
2、同步性
????Hashtable是線程同步的。這個類中的一些方法保證了Hashtable中的對象是線程安全的。而HashMap則是線程異步的,因此HashMap中的對象并不是線程安全的。因為同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那么使用HashMap是一個很好的選擇,這樣可以避免由于同步帶來的不必要的性能開銷,從而提高效率。
3、值
????HashMap可以讓你將空值作為一個表的條目的key或value但是Hashtable是不能放入空值的(null)
#### 進一步理解集合框架
????java的設計者給我們提供了這些集合類,在后面編程中是相當有用的,具體什么時候用什么集合,要根據我們剛才分析的集合異同來選取。
????如何選用集合類?
1、要求線程安全,使用Vector、Hashtable
2、不要求線程安全,使用ArrayList,LinkedList,HashMap
3、要求key和value鍵值,則使用HashMap,Hashtable
4、數據量很大,又要線程安全,則使用Vector
### Set結構的集合類
### HashSet類,TreeSet類
HashSet是基于HashMap實現的,HashSet底層采用HashMap來保存所有元素。
hashCode和equal()是HashMap用的,因為無需排序所以只需要關注定位和唯一性即可
hashCode是用來計算hash值的,hash值是用來確定hash表索引的
hash表中的一個索引存放的是一張鏈表,所以還要通過equal方法循環比較鏈上的每一個對象才可以真正定位到鍵值對應的Entry
put時,如果hash表中沒定位到,就在鏈表前加一個Entry,如果定位到了,則更換Entry中的value(值)并返回舊value(值)
覆寫key的hashCode()和equal()時一定要注意,不要把它們和可變屬性關聯上,否則屬性變了之后hashCode會變,equal也會為false,這樣在Map中就找不到它了而且這樣的對象因為找不到它所以得不到釋放,這樣就變成了一個無效引用(相當于內存泄漏)
#### HashSet集合類的使用方法
~~~
//Set結構常用的集合類
//HashSet --- 以HashMap為底層
//HashSet中無get方法,只能通過迭代器獲取鍵
HashSet hs = new HashSet();
//添加鍵到集合尾部
hs.add(str1);
hs.add(str2);
hs.add(str3);
//自動去掉重復元素,PS:其實也是像HashMap一樣,用新鍵覆蓋舊鍵
hs.add(str1);
//返回包含全部鍵的Object類型數組
Object[] o = hs.toArray();
for(int i = 0; i < o.length; i++){
System.out.print(o[i] + " ");
}
System.out.println();
~~~
TreeSet集合類是一個有序集合,它的元素按照升序排序,默認是自然順序排列,也就是說
TreeSet中的對象元素需要實現Comparable接口。TreeSet與HashSet類一樣沒有get()方法來獲取列表中的元素,所以也只能通過迭代器方法來獲取。
由于TreeMap需要排序,所以需要一個Comparator為鍵值進行大小比較,當然也是用Comparator定位的Comparator可以在創建TreeMap時指定,這時排序時使用Comparator.compare
如果創建時沒有指定Comparator那么就會使用key.compareTo()方法,這就要求key必須實現Comparable接口
TreeMap是使用Tree數據結構實現的,所以使用compare接口就可以完成定位了。
TreeSet是依靠TreeMap來實現的。
#### TreeSet集合類的使用方法
~~~
//TreeSet --- 使用元素的自然順序對元素進行排序,PS:自然順序是升序,或者根據創建 set時提供的 Comparator進行排序,具體取決于使用的構造方法
TreeSet ts = new TreeSet();
//添加鍵到集合
ts.add(str1);
ts.add(str2);
ts.add(str3);
//迭代器遍歷
for(it = ts.iterator(); it.hasNext();){
String tmp = it.next().toString();
System.out.print(tmp + " ");
}
System.out.println();
//返回此 set 中小于等于給定元素的最大元素;如果不存在這樣的元素,則返回 null。
ts.floor(str2);
//返回此 set 中大于等于給定元素的最小元素;如果不存在這樣的元素,則返回 null。
ts.ceiling(str2);
//返回此 set 中嚴格小于給定元素的最大元素;如果不存在這樣的元素,則返回 null。
ts.lower(str2);
//返回此 set 中嚴格大于給定元素的最小元素;如果不存在這樣的元素,則返回 null。
ts.higher(str2);
//獲取并移除第一個(最低)元素;如果此 set為空,則返回 null。
ts.pollFirst();
//獲取并移除最后一個(最高)元素;如果此 set為空,則返回 null。
ts.pollLast();
~~~
#### HashSet與TreeSet集合類的區別:
HashSet是基于hash算法實現的,性能優于TreeSet。通常使用HashSet,在我們需要對其中元素排序的時候才使用TreeSet。
### Queue結構的集合
### Queue接口
Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Queue接口。Queue接口窄化了對LinkedList的方法的訪問權限(即在方法中的參數類型如果是Queue時,就完全只能訪問Queue接口所定義的方法了,而不能直接訪問?LinkedList的非Queue的方法),以使得只有恰當的方法才可以使用。BlockingQueue繼承了Queue接口。
????隊列是一種數據結構。它有兩個基本操作:在隊列尾部加人一個元素,和從隊列頭部移除一個元素。就是說,隊列以一種先進先出的方式管理數據,如果你試圖向一個已經滿了的阻塞隊列中添加一個元素或者是從一個空的阻塞隊列中移除一個元索,將導致線程阻塞。
????在多線程進行合作時,阻塞隊列是很有用的工具。工作者線程可以定期地把中間結果存到阻塞隊列中而其他工作者線線程把中間結果取出并在將來修改它們。隊列會自動平衡負載。如果第一個線程集運行得比第二個慢,則第二個線程集在等待結果時就會阻塞。如果第一個線程集運行得快,那么它將等待第二個線程集趕上來。
<table><tbody><tr><td valign="top"><p><span style="font-size:18px">add</span></p></td><td valign="top"><p><span style="font-size:18px">增加一個元索</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列已滿,則拋出一個IIIegaISlabEepeplian異常</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">remove</span></p></td><td valign="top"><p><span style="font-size:18px">移除并返回隊列頭部的元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列為空,則拋出一個NoSuchElementException異常</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">element</span></p></td><td valign="top"><p><span style="font-size:18px">返回隊列頭部的元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列為空,則拋出一個NoSuchElementException異常</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">offer</span></p></td><td valign="top"><p><span style="font-size:18px">添加一個元素并返回true</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列已滿,則返回false</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">poll</span></p></td><td valign="top"><p><span style="font-size:18px">移除并返問隊列頭部的元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列為空,則返回null</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">peek</span></p></td><td valign="top"><p><span style="font-size:18px">返回隊列頭部的元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列為空,則返回null</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">put</span></p></td><td valign="top"><p><span style="font-size:18px">添加一個元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列滿,則阻塞</span></p></td></tr><tr><td valign="top"><p><span style="font-size:18px">take</span></p></td><td valign="top"><p><span style="font-size:18px">移除并返回隊列頭部的元素</span></p></td><td valign="top"><p><span style="font-size:18px">如果隊列為空,則阻塞</span></p></td></tr><tr><td width="585" valign="top" colspan="3"><p><span style="color:rgb(255,0,0)"><span style="font-size:18px">remove、element、offer?、poll、peek?其實是屬于Queue接口。?</span></span></p></td></tr></tbody></table>
阻塞隊列的操作可以根據它們的響應方式分為以下三類:add、remove和element操作在你試圖為一個已滿的隊列增加元素或從空隊列取得元素時?拋出異常。當然,在多線程程序中,隊列在任何時間都可能變成滿的或空的,所以你可能想使用offer、poll、peek方法。這些方法在無法完成任務時?只是給出一個出錯示而不會拋出異常。
注意:poll和peek方法出錯進返回null。因此,向隊列中插入null值是不合法的。
### offer,add區別:
一些隊列有大小限制,因此如果想在一個滿的隊列中加入一個新項,多出的項就會被拒絕。這時新的?offer?方法就可以起作用了。它不是對調用?add()?方法拋出一個?unchecked?異常,而只是得到由?offer()?返回的?false。
### poll,remove區別:
remove()和poll()方法都是從隊列中刪除第一個元素(head)。remove()的行為與Collection?接口的版本相似,但是新的?poll()方法在用空集合調用時不是拋出異常,只是返回null。因此新的方法更適合容易出現異常條件的情況。
### peek,element區別:
element()和peek()用于在隊列的頭部查詢元素。與?remove()方法類似,在隊列為空時,element()拋出一個異常,而peek()返回null。
### 五個隊列所提供的各有不同:
#### *?ArrayBlockingQueue?:
一個由數組支持的有界隊列。基于數組的阻塞循環隊列,先進先出原則對元素進行排序。
#### *?LinkedBlockingQueue:
一個由鏈接節點支持的可選有界隊列。基于鏈表的隊列,先進先出排序元素。
#### *?PriorityBlockingQueue:
一個由優先級堆支持的無界優先級隊列。PriorityBlockingQueue是對PriorityQueue的再次包裝,是基于堆數據結構的,而PriorityQueue是沒有容量限制的,與ArrayList一樣,所以在優先阻塞隊列上put時是不會受阻的。但是由于資源被耗盡,所以試圖執行添加操作可能會導致OutOfMemoryError),但是如果隊列為空,那么取元素的操作take就會阻塞,所以它的檢索操作take是受阻的。另外,往入該隊列中的元素要具有比較能力。
#### *?DelayQueue:
一個由優先級堆支持的、基于時間的調度隊列。(基于PriorityQueue來實現的)是一個存放Delayed?元素的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部是延遲期滿后保存時間最長的?Delayed?元素。如果延遲都還沒有期滿,則隊列沒有頭部,并且poll將返回null。當一個元素的?getDelay(TimeUnit.NANOSECONDS)?方法返回一個小于或等于零的值時,則出現期滿,poll就以移除這個元素了。此隊列不允許使用null元素。
#### *?SynchronousQueue:
一個利用?BlockingQueue接口的簡單聚集(rendezvous)機制。
SynchronousQueue?類是最簡單的。它沒有內部容量。它就像線程之間的手遞手機制。在隊列中加入一個元素的生產者會等待另一個線程的消費者。當這個消費者出現時,這個元素就直接在消費者和生產者之間傳遞,永遠不會加入到阻塞隊列中。
注意:Queue隊列是不能直接實例化的。
### 總結
### Java中的List/Set和Map的區別
????List按對象進入的順序保存對象,不做排序和編輯操作。
????Set對每個對象只接受一次,并使用自己內部的排序方法(通常,你只關心某個元素是否屬于Set而不關心它的順序--否則使用List)。
????Map同樣對每個元素保存一份,但這是基于"鍵"(key)的,Map也有內置的排序,因而不關心元素添加的順序。
如果添加元素的順序對程序設計很重要,應該使用LinkedHashSet或者LinkedHashMap。
### List的功能方法
????實際上有兩種List:一種是基本的ArrayList其優點在于隨機訪問元素,另一種是更強大的LinkedList它并不是為快速隨機訪問設計的,而是具有一套更通用的方法。
????List:次序是List最重要的特點:它保證維護元素特定的順序。List為Collection添加了許多方法,使得能夠向List中間插入與移除元素(這只推薦LinkedList使用)一個List可以生成Listlterator,使用它可以從兩個方向遍歷List,也可以從List中間插入和移除元素。
????ArrayList:由數組實現的List。允許對元素進行快速隨機訪問,但是向List中間插入與移除元素的速率很慢。Listlterator只應該用來由后向前遍歷ArrayList。而不是用來插入和移除元素。因為那比LinkedList開銷要大很多。
????LinkedList:對順序訪問進行了優化,向List中間插入與刪除的開銷并不大。隨機訪問則相對較慢。(使用ArrayList代替)還具有下列方法:addFirst(),addLast(),getFirst(),getLast(),removeFirst()和removeLast()這些方法(沒有在任何接口或基類中定義過)使得LinkedList可以當作堆棧、隊列和雙向隊列使用。
### Set的功能方法
????Set具有與Collection完全一樣的接口,因此沒有任何額外的功能,不象前面有兩個不同的List。實際上Set就是Collection,只是行為不同。(這是繼承與多態思想的典型應用:表現不同的行為。)Set不保存重復的元素(至于如何判斷元素相同則較為負責)
??Set:存入Set的每個元素都必須是唯一的,因為Set不保存重復元素。加入Set的元素必需定義equals()方法以確保對象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護元素的次序。
??HashSet:為快速查找設計的Set。存入HashSet的對象必須定義hashCode()。
?TreeSet:保存次序的Set,底層為樹結構。使用它可以從Set中提取有序的序列。
????LinkedHashSet:具有HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。于是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。
### Map的功能方法
????方法put(Object?key,Object?value)添加一個"值"(想要得東西)和與"值"相關的"鍵"(key)(使用它來查找)。方法get(Object?key)返回與給定"鍵"相關聯的"值"。可以用containsKey()和containsValue()測試Map中是否包含某個"鍵"或"值"。標準的java類庫中包含了幾種不同的Map:HashMap,TreeMap,LinkedHashMap,WeakHashMap,ldentityHashMap。它們都有同樣的基本接口Map,但是行為、效率、排序策略、保存對象的生命周期和判定"鍵"等價的策略等各不相同。
????執行效率是Map的一個大問題。看看get()要做哪些事,就會明白為什么在ArrayList中搜索"鍵"是相當慢的。這正是HashMap提高速度的地方。HashMap使用了特殊的值,稱為"散列碼"(hash?code),來取代對鍵的緩慢搜索。"散列碼"是"相對唯一"用以代表對象的int值,它是通過將該對象的某些信息進行轉換而生成的。所有java對象都能產生散列碼,因為hashCode()是定義在基類Object中的方法。
????HashMap就是使用對象的hashCode()進行快速查詢的。此方法能夠顯著提高性能。
????Map:維護"鍵值對"的關聯性,使你可通過"鍵"查找"值"
????HashMap:Map基于散列表的實現。插入和查詢"鍵值對"的開銷是固定的。可以通過構造器設置容量capacity和負載因子load?factor,以調整容器的性能。
????LinkedHashMap:類似于HashMap,但是迭代遍歷它時,取得"鍵值對"的順序是其插入次序,或者是最近最少使(LRU)的次序。只能HashMap慢一點。而在迭代訪問時發而更快,因為它使用鍵表維護內部次序。
????TreeMap:基于紅黑樹數據結果的實現。查看"鍵"或"鍵值對"時,它們會被排序(次序由Comparabel或Comparator決定)。TreeMap的特點在于,你得到的結果是經過排序的。TreeMap是唯一的帶有subMap()方法的Map,它可以返回一個子樹。
-------------參考《韓順平.循序漸進學.java.從入門到精通》
-------------參考《JDK_API_1_6_zh_CN》
Java學習筆記--導航[http://blog.csdn.net/q547550831/article/details/49819641](http://blog.csdn.net/q547550831/article/details/49819641)