Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMapphp
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中每個元素。典型的用法以下:
Iterator it = collection.iterator(); // 得到一個迭代子
while(it.hasNext()) {
Object obj = it.next(); // 獲得下一個元素
}
由Collection接口派生的兩個接口是List和Set。html
讓咱們轉到對框架實現的研究,具體的集合類遵循命名約定,並將基本數據結構和框架接口相結合。除了四個歷史集合類外,Java 2 框架還引入了六個集合實現,以下表所示。關於歷史集合類如何轉換、好比說,如何修改Hashtable
並結合到框架中,請參閱歷史集合類 。java
接口 | 實現 | 歷史集合類 |
Set |
HashSet |
|
TreeSet |
||
List |
ArrayList |
Vector |
LinkedList |
Stack |
|
Map |
HashMap |
Hashtable |
TreeMap |
Properties |
這裏沒有 Collection
接口的實現。歷史集合類,之因此這樣命名是由於從 Java 類庫 1.0 發行版就開始沿用至今了。程序員
若是從歷史集合類轉換到新的框架類,主要差別之一在於全部的操做都和新類不一樣步。您能夠往新類中添加同步的實現,但您不能把它從舊的類中除去。面試
Collection collection = new ArrayList();(這樣寫的好處在於,之後若是要理性不一樣的集合,能夠省略不少麻煩。由於都是用Collection接口裏的方法,)算法
boolean |
add(E o) 確保此 collection 包含指定的元素(可選操做)。 |
|
boolean |
addAll(Collection<? extends E> c) 將指定 collection 中的全部元素都添加到此 collection 中(可選操做)。 |
|
void |
clear() 移除此 collection 中的全部元素(可選操做)。 |
|
boolean |
contains(Object o) 若是此 collection 包含指定的元素,則返回 true。 |
|
boolean |
containsAll(Collection<?> c) 若是此 collection 包含指定 collection 中的全部元素,則返回true。 |
|
boolean |
equals(Object o) 比較此 collection 與指定對象是否相等。 |
|
int |
hashCode() 返回此 collection 的哈希碼值。 |
|
boolean |
isEmpty() 若是此 collection 不包含元素,則返回 true。 |
|
Iterator<E> |
iterator() 返回在此 collection 的元素上進行迭代的迭代器。 |
|
boolean |
remove(Object o) 今後 collection 中移除指定元素的單個實例,若是存在的話(可選操做)。 |
|
boolean |
removeAll(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的全部元素(可選操做)。 |
|
boolean |
retainAll(Collection<?> c) 僅保留此 collection 中那些也包含在指定 collection 的元素(可選操做)。 |
|
int |
size() 返回此 collection 中的元素數。 |
|
Object[] |
toArray() 返回包含此 collection 中全部元素的數組。 |
|
|
toArray(T[] a) 返回包含此 collection 中全部元素的數組;返回數組的運行時類型與指定數組的運行時類型相同。 |
*All方法參數的類型都爲Collection ,大多數方法都是返回boolean類型值,Collection 接口用於表示任何對象或元素組。想要儘量以常規方式處理一組元素時,就使用這一接口。(如,能夠直接add(100),能夠是普通數據類型)。編程
容器類對象在調用remove,contains等方法時須要比較對象是否相等地,這會涉及到對象類型的equals方法和hashcode方法。即,相等的對象應該有相等的hashcode.固然,若是是自定義的類型,須要重寫這兩個方法。api
iterator接口數組
boolean |
hasNext() 若是仍有元素能夠迭代,則返回 true。 |
E |
next() 返回迭代的下一個元素。 |
void |
remove() 從迭代器指向的集合中移除迭代器返回的最後一個元素(可選操做)。 |
boolean |
add(E o) 若是 set 中還沒有存在指定的元素,則添加此元素(可選操做)。 |
|
boolean |
addAll(Collection<? extends E> c) 若是 set 中沒有指定 collection 中的全部元素,則將其添加到此 set 中(可選操做)。 |
|
void |
clear() 移除 set 中的全部元素(可選操做)。 |
|
boolean |
contains(Object o) 若是 set 包含指定的元素,則返回 true。 |
|
boolean |
containsAll(Collection<?> c) 若是此 set 包含指定 collection 的全部元素,則返回 true。 |
|
boolean |
equals(Object o) 比較指定對象與此 set 的相等性。 |
|
int |
hashCode() 返回 set 的哈希碼值。 |
|
boolean |
isEmpty() 若是 set 不包含元素,則返回 true。 |
|
Iterator<E> |
iterator() 返回在此 set 中的元素上進行迭代的迭代器。 |
|
boolean |
remove(Object o) 若是 set 中存在指定的元素,則將其移除(可選操做)。 |
|
boolean |
removeAll(Collection<?> c) 移除 set 中那些包含在指定 collection 中的元素(可選操做)。 |
|
boolean |
retainAll(Collection<?> c) 僅保留 set 中那些包含在指定 collection 中的元素(可選操做)。 |
|
int |
size() 返回 set 中的元素數(其容量)。 |
|
Object[] |
toArray() 返回一個包含 set 中全部元素的數組。 |
|
|
toArray(T[] a) 返回一個包含 set 中全部元素的數組;返回數組的運行時類型是指定數組的類型。 |
按照定義,Set
接口繼承 Collection
接口,並且它不容許集合中存在重複項。全部原始方法都是現成的,沒有引入新方法。具體的Set
實現類依賴添加的對象的 equals()
方法來檢查等同性。安全
HashSet 類和 TreeSet 類
「集合框架」支持 Set
接口兩種普通的實現:HashSet
和TreeSet
。在更多狀況下,您會使用 HashSet
存儲重複自由的集合。考慮到效率,添加到 HashSet
的對象須要採用恰當分配散列碼的方式來實現hashCode()
方法。雖然大多數系統類覆蓋了 Object
中缺省的hashCode()
實現,但建立您本身的要添加到 HashSet
的類時,別忘了覆蓋 hashCode()
。當您要從集合中以有序的方式抽取元素時,TreeSet
實現會有用處。爲了能順利進行,添加到TreeSet
的元素必須是可排序的。 「集合框架」添加對 Comparable
元素的支持,在排序的「可比較的接口」部分中會詳細介紹。咱們暫且假定一棵樹知道如何保持java.lang
包裝程序器類元素的有序狀態。通常說來,先把元素添加到 HashSet
,再把集合轉換爲TreeSet
來進行有序遍歷會更快。
爲優化 HashSet
空間的使用,您能夠調優初始容量和負載因子。TreeSet
不包含調優選項,由於樹老是平衡的,保證了插入、刪除、查詢的性能爲log(n)
。
HashSet
和 TreeSet
都實現 Cloneable
接口。
集的使用示例
爲演示具體 Set
類的使用,下面的程序建立了一個 HashSet
,並往裏添加了一組名字,其中有個名字添加了兩次。接着,程序把集中名字的列表打印出來,演示了重複的名字沒有出現。接着,程序把集做爲TreeSet
來處理,並顯示有序的列表。
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]
List
接口繼承了 Collection
接口以定義一個容許重複項的有序集合。該接口不但可以對列表的一部分進行處理,還添加了面向位置的操做。
有序的 collection(也稱爲序列)。此接口的用戶能夠對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。
與 set 不一樣,列表一般容許重複的元素。更正式地說,列表一般容許知足 e1.equals(e2) 的元素對 e1 和 e2,而且若是列表自己容許 null 元素的話,一般它們容許多個 null 元素。不免有人但願經過在用戶嘗試插入重複元素時拋出運行時異常的方法來禁止重複的列表,但咱們但願這種用法越少越好。
List 接口在 iterator、add、remove、equals 和 hashCode 方法的協定上加了一些其餘約定,超過了 Collection 接口中指定的約定。爲方便起見,這裏也包括了其餘繼承方法的聲明。
List 接口提供了 4 種對列表元素進行定位(索引)訪問方法。列表(像 Java 數組同樣)是基於 0 的。注意,這些操做可能在和某些實現(例如 LinkedList 類)的索引值成比例的時間內執行。所以,若是調用方不知道實現,那麼在列表元素上迭代一般優於用索引遍歷列表。
List 接口提供了特殊的迭代器,稱爲 ListIterator,除了容許 Iterator 接口提供的正常操做外,該迭代器還容許元素插入和替換,以及雙向訪問。還提供了一個方法來獲取從列表中指定位置開始的列表迭代器。
List 接口提供了兩種搜索指定對象的方法。從性能的觀點來看,應該當心使用這些方法。在不少實現中,它們將執行高開銷的線性搜索。
List 接口提供了兩種在列表的任意位置高效插入和移除多個元素的方法。
注意:儘管列表容許把自身做爲元素包含在內,但建議要特別當心:在這樣的列表上,equals 和 hashCode 方法再也不是定義良好的。
某些列表實現對列表可能包含的元素有限制。例如,某些實現禁止 null 元素,而某些實現則對元素的類型有限制。試圖添加不合格的元素會拋出未經檢查的異常,一般是 NullPointerException 或 ClassCastException。試圖查詢不合格的元素是否存在可能會拋出異常,也可能簡單地返回 false;某些實現會採用前一種行爲,而某些則採用後者。歸納地說,試圖對不合格元素執行操做時,若是完成該操做後不會致使在列表中插入不合格的元素,則該操做可能拋出一個異常,也可能成功,這取決於實現的選擇。此接口的規範中將這樣的異常標記爲「可選」。
面向位置的操做包括插入某個元素或 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 }
此外,咱們還應該提醒的是 ― 對子列表的更改(如 add()
、remove()
和 set()
調用)對底層 List
也有影響。
boolean |
add(E o) 向列表的尾部追加指定的元素(可選操做)。 |
|
void |
add(int index, E element) 在列表的指定位置插入指定元素(可選操做)。 |
|
boolean |
addAll(Collection<? extends E> c) 追加指定 collection 中的全部元素到此列表的結尾,順序是指定 collection 的迭代器返回這些元素的順序(可選操做)。 |
|
boolean |
addAll(int index, Collection<? extends E> c) 將指定 collection 中的全部元素都插入到列表中的指定位置(可選操做)。 |
|
void |
clear() 從列表中移除全部元素(可選操做)。 |
|
boolean |
contains(Object o) 若是列表包含指定的元素,則返回 true。 |
|
boolean |
containsAll(Collection<?> c) 若是列表包含指定 collection 的全部元素,則返回 true。 |
|
boolean |
equals(Object o) 比較指定的對象與列表是否相等。 |
|
E |
get(int index) 返回列表中指定位置的元素。 |
|
int |
hashCode() 返回列表的哈希碼值。 |
|
int |
indexOf(Object o) 返回列表中首次出現指定元素的索引,若是列表不包含此元素,則返回 -1。 |
|
boolean |
isEmpty() 若是列表不包含元素,則返回 true。 |
|
Iterator<E> |
iterator() 返回以正確順序在列表的元素上進行迭代的迭代器。 |
|
int |
lastIndexOf(Object o) 返回列表中最後出現指定元素的索引,若是列表不包含此元素,則返回 -1。 |
|
ListIterator<E> |
listIterator() 返回列表中元素的列表迭代器(以正確的順序)。 |
|
ListIterator<E> |
listIterator(int index) 返回列表中元素的列表迭代器(以正確的順序),從列表的指定位置開始。 |
|
E |
remove(int index) 移除列表中指定位置的元素(可選操做)。 |
|
boolean |
remove(Object o) 移除列表中出現的首個指定元素(可選操做)。 |
|
boolean |
removeAll(Collection<?> c) 從列表中移除指定 collection 中包含的全部元素(可選操做)。 |
|
boolean |
retainAll(Collection<?> c) 僅在列表中保留指定 collection 中所包含的元素(可選操做)。 |
|
E |
set(int index, E element) 用指定元素替換列表中指定位置的元素(可選操做)。 |
|
int |
size() 返回列表中的元素數。 |
|
List<E> |
subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分視圖。 |
|
Object[] |
toArray() 返回以正確順序包含列表中的全部元素的數組。 |
|
|
toArray(T[] a) 返回以正確順序包含列表中全部元素的數組;返回數組的運行時類型是指定數組的運行時類型。 |
其中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是一種老的動態數組,是線程同步的,效率很低,通常不同意使用。
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
接口的歷史實現。咱們將在Dictionary 類、Hashtable 類和 Properties 類中討論。
映射的使用示例
如下程序演示了具體 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); } }
用 Bill of Rights 的第三篇文章的文本運行程序產生下列輸出,請注意有序輸出看起來多麼有用!
無序輸出:
{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}
Java集合框架是最常被問到的Java面試問題,要理解Java技術強大特性就有必要掌握集合框架。這裏有一些實用問題,常在覈心Java面試中問到。
一、什麼是Java集合API
Java集合框架API是用來表示和操做集合的統一框架,它包含接口、實現類、以及幫助程序員完成一些編程的算法。簡言之,API在上層完成如下幾件事:
● 編程更加省力,提升城程序速度和代碼質量
● 非關聯的API提升互操做性
● 節省學習使用新API成本
● 節省設計新API的時間
● 鼓勵、促進軟件重用
具體來講,有6個集合接口,最基本的是Collection接口,由三個接口Set、List、SortedSet繼承,另外兩個接口是Map、SortedMap,這兩個接口不繼承Collection,表示映射而不是真正的集合。
二、什麼是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。