轉載:java
一:集合的概念程序員
集合:保存數量不肯定的數據,以及保存具備映射關係的數據的容器,簡單的理解就是用於存儲數量不等的多個對象的容器。算法
集合和數組不同,數組元素既能夠是基本類型的值,也能夠是對象(對象的引用變量);而集合裏只能保存對象(對象的引用變量)。編程
Java集合類主要由兩個集合框架的根接口派生而出:Collection和Map數組
Java中Collection接口的體系機構:安全
Collection接口和Iterator接口:數據結構
Collection接口是List、Set和Queue接口的父接口,該接口中定義了一些操做集合元素的方法:框架
下面列舉一些常見的方法:ide
boolean add(Object o):該方法用於向集合裏添加一個元素。函數
boolean addAll(Collection c):該方法把集合c裏的全部元素添加到指定的集合裏。
void clean():清除集合裏的全部元素,將集合長度變爲0。
boolean contains():返回集合裏是否包含指定元素。
boolean containsAll():返回集合裏是否包含集合c裏的全部元素。
boolean isEmpty():返回集合是否爲空。當集合長度爲0時返回true,不然返回false。
Iterator iterator():返回一個Iterator對象,用於遍歷集合中的元素。
boolean remove(Object o):刪除集合中指定的元素o,當集合中包含了一個或多個元素o時,這些元素將被刪除,該方法將返回true。
boolean removeAll(Collection c):從集合中刪除集合c裏包含的全部元素。
boolean retainAll(Collection c):從集合中刪除集合c裏不包含的元素(至關於取得把調用該方法的集合變爲該集合和集合c的交集),若是該操做改變了調用該方法的集合,返回true。
int size():該方法返回集合裏元素的個數。
Object[] toArray():該方法把集合轉換成一個數組,全部集合元素變成對應的數組元素。
Iterator接口:
Iterator接口也是Java集合框架的成員,但它與Collection系列、Map系列的集合不同:Collection系列集合和Map系列的集合主要用於盛裝其餘對象,而Iterator則主要用於遍歷集合的元素。又叫迭代器。
Iterator接口隱藏了各類Collection實現類的底層細節,只嚮應用程序提供遍歷集合元素的統一編程接口。
Iterator接口定義了三個方法:
boolean hasNext():若是被迭代的集合元素還有沒遍歷,則返回true。
Object next():返回集合裏的下一個元素。
void remove():刪除集合裏上一次next方法返回的元素。
Iterator僅用於遍歷集合,若是須要建立Iterator對象,則必須有一個被迭代的集合。沒有集合和Iterator彷彿無本之木,沒有存在的意義。
當使用Iterator對集合元素進行迭代時,Iterator並非把集合元素本事傳給了迭代變量,而是把集合元素的值傳給了迭代變量,因此修改迭代變量的值對集合元素本事沒有影響。
當使用Iterator來迭代訪問Collection集合元素時,Collection集合裏的元素不能被修改,只能經過remove方法刪除上次next方法返回的集合元素才能夠,不然報java.util.ConcurrentModificationException異常。
Iterator迭代器採用的是快速失敗(fail-fast)機制,一旦在迭代過程當中檢測到該集合已經被修改(一般是其餘線程進行修改),程序將報java.util.ConcurrentModificationException異常。而不是顯示修改後的結果,這樣能夠避免共享資源而引起的問題。
foreach循環變量集合元素
格式:
for(類型 新對象:集合){
}
用法和Iterator相似。
二:Set接口
Set集合是無順序的,其集合元素不容許重複。
Set集合判斷兩個對象相同不是使用==運算符,而是根據equals方法。簡單的說,若是隻要兩個對象用equals方法比較返回true,Set集合就不會接受這兩個對象;反之,則成立。
HashSet類:
HashSet是Set集合的實現類,HashSet按Hash算法來存儲集合中的元素,所以具備很好的存取和查找性能。
HashSet集合特色:
(1)不能保證元素的排列順序,順序有可能發生變化。
(2)HashSet不是同步的,若是多個線程同時訪問一個HashSet,若是有2條或2條以上線程同時修改HashSet集合時,必須經過代碼實現線程同步。
(3)集合元素值能夠是null。
向HastSet集合中存入一個元素時,HashSet會調用該對象的hashCode()方法來獲得該對象的hashCode值,而後根據該HashCode值來決定該對象在HashSet中存儲位置。若是有兩個元素經過equals方法比較返回true,但它們的hashCode()方法返回值不相等,HashSet將會把它們存儲在不一樣的位置,就能夠添加成功(簡單的理解HastSet集合判斷兩個元素是否相等的標準是兩個對象經過equals方法比較相等,且兩個對象的hashCode()方法返回的值也要相等)。
TreeSet類:
TreeSet是SortedSet接口的惟一實現,TreeSet能夠確保集合元素處於排序狀態。
TreeSet新添的方法:
(1)Comparator comparator():返回當前Set使用的Comparator,或者返回null,表示以天然方式排序。
(2)Object first():返回集合中的第一個元素。
(3)Object last():返回集合中的最後一個元素。
(4)Object lower(Object e):返回集合中位於指定元素以前的元素。
(5)Object higher(Object e):返回集合中位於指定元素以後的元素。
(6)SortedSet subSet(fromElement,toElement):返回此Set的子集合,範圍衝fromElement(包含)到toElement(不包含)。
(7)SortedSet headSet(toElement):返回此Set的子集,由小於toElement的元素組成。
(8)SortedSet tailSet(fromElement):返回此Set的子集,由大於或等於fromElement的元素組成。
TreeSet集合並非根據元素的插入順序進行排序,而是根據元素實際值進行排序。
TreeSet集合採用紅黑樹的數據結構對元素進行排序。TreeSet集合支持兩種排序方法:天然排序和定製排序。默認使用天然排序。
天然排序
TreeSet調用集合元素的compareTo(Object obj)方法來比較元素之間大小關係,而後將集合元素按升序排列,這就是天然排序。
Java提供了一個Comparable接口,該接口裏定義了一個compareTo(Object obj)方法,該方法返回一個整數,實現該接口的類必須實現該方法,當一個對象調用該方法與另外一個對象進行比較時,好比:obj1.compareTo(obj2),若是該方法返回0,則代表兩個對象相等,若是返回是一個正整數,則代表obj1大於obj2,若是返回是一個負數,則代表obj1小於obj2。
注意:向TreeSet集合中添加元素時,只有第一個元素能夠不實現Comparable接口,後面添加的全部元素都必須實現Comparable接口。不然報ClassCastException異常。
當把一個對象加入TreeSet集合中時,TreeSet調用該對象的compareTo方法與集合中的其餘對象比較大小,而後根據紅黑樹算法決定它存儲的位置。若是兩個對象相等,TreeSet將把他們存儲在同一位置。TreeSet集合比較兩個對象相等的標準是:兩個對象經過equals方法返回true,或經過compareTo方法比較返回0,則認爲兩個對象是同一個對象。
定製排序
經過實現Comparator接口中的compare方法來實現集合的定製排序,
int compare(T o1,T o2)方法比較大小,若是返回是正整數,則代表o1大於o2,若是返回0,則代表兩個對象相等,若是返回負數,則代表o1小於o2。
若是須要實現定製排序,則須要在建立TreeSet集合對象時,並提供一個Comparator對象與該集合關聯,由該Comparator對象負責集合的排序邏輯。
經典實例
public class TreeSetTest {
public static void main(String[] args) {
//定義TreeSet集合,併爲集合提供一個排序的Comparator對象(這裏是匿名內部類)。
TreeSet<M> ts = new TreeSet<M>(new Comparator<M>() {
@Override
public int compare(M m1, M m2) {
// TODO Auto-generated method stub
if (m1.num > m2.num) {
return -1;//這是按降序排序,若是想按升序排序,這裏返回正整數,下面else中返回負數,便可。
} else if (m1.num == m2.num) {
return 0;
} else {
return 1;
}
}
});
//向集合中添加數據
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(8));
ts.add(new M(6));
System.out.println(ts);
}
}
class M {
// 定義一個變量
int num;
public M(int num) {
// 構造函數中爲變量賦值
this.num = num;
}
// 重寫toString方法
public String toString() {
return "M對象num的值爲" + this.num;
}
}
EnumSet類
EnumSet類是一個專爲枚舉類設計的集合類,EnumSet中全部的元素都必須是指定枚舉類型的枚舉值,該枚舉類型在建立EnumSet時顯式或隱式地指定。EnumSet的集合元素也是有序的,EnumSet以枚舉值在Enum類內的定義順序來決定集合元素的順序。EnumSet集合不容許插入null元素。
EnumSet集合的內部一位向量的形式存儲,這種存儲形式很是緊湊、高效,所以EnumSet對象佔用內存很小,並且運行效率很好。具體體如今批量操做集合時。
EnumSet類沒有暴露任何構造函數來建立該類的實例,程序經過它提供的static方法來建立EnumSet對象。
EnumSet集合經常使用的方法
(1)static EnumSet allOf(Class elementType):建立一個包含指定枚舉類裏全部枚舉值的EnumSet集合。
(2)static EnumSet complementOf(EnumSet s):建立一個其元素類型與指定EnumSet裏元素類型相同的EnumSet,新EnumSet集合包含原EnumSet集合所不包含的、此枚舉類剩下的枚舉值。
(3)static EnumSet copyOf(Collection c):使用一個普通集合來建立EnumSet集合。
(4)static EnumSet copyOf(EnumSet s):建立一個與指定EnumSet具備相同元素類型、相同集合元素的EnumSet。
(5)static EnumSet noneOf(Class elementType):建立一個元素類型爲指定枚舉類型的空EnumSet。
(6)static EnumSet of(E first,E...rest):建立一個包含一個或多個枚舉值的EnunSet,傳入的多個枚舉值必須屬於同一個枚舉類。
(7)static EnumSet range(E from,E to):建立包含從from枚舉值,到to枚舉值範圍內全部枚舉值的EnumSet集合。
經典實例:
public class EnumSetTest {
public static void main(String[] args) {
EnumSet<Season> es=EnumSet.allOf(Season.class);
System.out.println(es);//打印[SPRING, SUMMER, FAILL, WINTER]
EnumSet<Season> es1=EnumSet.of(Season.SPRING,Season.SUMMER,Season.WINTER);
System.out.println(es1);//打印[SPRING, SUMMER, WINTER]
EnumSet<Season> es2=EnumSet.range(Season.SUMMER, Season.WINTER);
System.out.println(es2);//打印[SUMMER, FAILL, WINTER]
EnumSet<Season> es3=EnumSet.complementOf(es2);
System.out.println(es3);//打印[SPRING]
}
}
enum Season{
SPRING,SUMMER,FAILL,WINTER
}
總結
HashSet和TreeSet是Set的兩個典型實現,HashSet的性能總比TreeSet好(添加,查詢操做),由於TreeSet須要額外的紅黑樹算法來維護集合元素的次序。TreeSet是有序的集合。
HashSet還有一個子類LinkedHashSet,對於普通的插入,刪除操做,LinkedHashSet比HashSet要慢一點點,這是由於維護鏈表所帶來的開銷。不過遍歷集合時,LinkedHashSet就很是塊 。
EnumSet是全部Set實現類中性能最好 ,但它只能保存同一個枚舉類的枚舉值做爲集合元素。
注意:Set的三個實現類HashSet 、TreeSet、EnumSet都是線程不安全的。若是有多條線程同事訪問一個Set集合,而且有超過一條線程修改集合的值,則必須手動保證集合的同步性,不然將沒法訪問修改後的集合。
List接口
List集合表明一個有序的集合 ,集合中每一個元素都有其對應的順序索引。List集合容許使用重複元素,經過索引來訪問指定位置的集合元素。
List集合在Collection的基礎上新添加的方法:
(1)void add (int index,Object element):將元素element插入在List集合的index處。
(2)boolean addAll(int index,Collection c):將集合c所包含的全部元素都插入在List集合的Index處。
(3)Object get(int index):返回集合index索引處的元素。
(4)int indexOf(Object o):返回對象o在List集合中出現的位置索引。
(5)int lastIndexOf(Object o):返回對象o在List集合中最後一次出現的位置索引。
(6)Object remove(int index):刪除並返回index索引處的元素。
(7)Object set(int index,Object element):將index索引處的元素替換成element對象,返回新元素。
(8)List subList(int fromIndex,int toIndex):返回從索引fromIndex(包含)到索引toIndex(不包含)處全部集合元素組成的子集合。
ListIterator接口:
ListIterator接口是Iterator的子接口,提供了專門操做List的方法。
ListIterator接口新增的方法:
(1)boolean hasPrevious():返回該迭代器關聯的集合是否還有上一個元素。
(2)Object previous():返回該迭代器的上一個元素。
(3)void add():在指定位置插入一個元素。
根據上面的三個方法和解釋,不難發現ListIterator新增長了向前迭代的功能,並且ListIterator還能夠經過add方法向List集合中添加元素。
經典實例:
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("smarhit");
list.add("heima");
list.add("sichuan");
list.add("chengdu");
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
System.out.print(lit.next()+"\t");
}
System.out.println("\n----------開始反向迭代--------------");
while (lit.hasPrevious()) {
System.out.print(lit.previous()+"\t");
}
/*
* 打印的結果是:
* smarhit heima sichuan chengdu
* ----------開始反向迭代--------------
* chengdu sichuan heima smarhit
*/
}
}
ArrayList和Vector實現類
ArrayList和Vector類都是基於數組實現的List類,ArrayList和Vector類封裝了一個動態在分配的Object[ ]數組。每一個ArrayList或Vector對象有一個capacity屬性,該屬性表示他們所封裝的數組的長度,當想ArrayList或Vector中添加元素時,它們的capacity會自動增長。對於一般編程中,程序員無須關心ArrayList或Vector的capacity屬性。但若是向ArrayList集合或Vector集合中添加大量元素時,可以使用ensureCapacity方法一次性的增長capacity。這樣能夠提升性能。
ArrayList和Vector在用法上幾乎徹底相同(Vector是古老的集合,JDK1.0就存在了),但ArrayList集合是線程不安全的,當多條線程訪問同一個集合時,若是有超過一條線程修改了ArrayList集合,則程序必須手動保證該集合的同步性。而Vector集合則是線程安全的。無須程序保證集合的同步性。因此Vector的性能比ArrayList的性能低。
Vector還提供了一個Stack子類,它用於模擬了「棧」這中數據結構,「棧」一般是指「後進先出」的容器。最後「push」進棧的元素,將最早被「pop」出棧。
Stack類提供的方法:
(1)Object peek():返回「棧」的第一個元素,但並不將該元素"pop"出棧。
(2)Object pop():返回"棧"的第一個元素,並將該元素"pop"出棧。
(3)void push(Object item):將一個元素「push」進棧,最後一個進「棧」的元素老是位於「棧」頂。
經典實例:
public class StackTest {
public static void main(String[] args) {
Stack<String> s=new Stack<String>();
s.push("smarhit");
s.push("beijin");
s.push("neijiang");
s.push("chengdu");
System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]
System.out.println(s.peek());//打印chengdu
System.out.println(s);//打印[smarhit, beijin, neijiang, chengdu]
System.out.println(s.pop());//打印chengdu
System.out.println(s);//打印[smarhit, beijin, neijiang]
}
}
固定長度的List
數組的工具類 Arrays提供的asList()方法是把一個數組或指定個數的對象轉換成一個List集合, 但這個List集合既不是ArrayList實現類的實例,也不是Vector實現類的實例,而是Arrays的內部類ArrayList實例。Arrays.ArrayList是一個固定長度的List集合,程序只能遍歷訪問該集合裏的元素,不可增長,刪除該集合中的元素。
Queue接口
Queue模擬了隊列這中數據結構,隊列一般是"先進先出"的容器。
Queue接口提供的方法:
(1)void add(Object e):將指定元素加入此隊列的尾部。
(2)Object element():獲取隊列頭部的元素,但不是刪除該元素。
(3)boolean offer(Object e):將指定元素加入此隊列的尾部。當使用有容器限制的隊列時,此方法一般比add(Object e)方法更好。
(4)Object peek():獲取隊列頭部的元素,可是不刪除該元素。若是此隊列爲空,則返回null。
(5)Object poll():獲取隊列頭部的元素,並刪除該元素。若是此隊列爲空,則返回null。
(6)Object remove():獲取隊列頭部元素,並刪除該元素。
LinkedList實現類:
LinkedList類是一個比較特殊的類,它實現了List接口,還實現了Deque接口,Deque接口是Queue接口的子接口,它表明一個雙向隊列。
LinkedList類提供的方法:
(1)void addFirst(Object e):將指定元素插入該雙向隊列的開頭。
(2)void addLast(Object e):將指定元素插入該雙向隊列的尾部。
(3)Iterator descendingIterator():返回以該雙向隊列對應的迭代器,該迭代器將以逆向順序來迭代隊列中的元素。
(4)Object getFirst():獲取、但不刪除雙向隊列的第一個元素。
(5)Object getLast():獲取、但不刪除雙向隊列的最後一個元素。
(6)boolean offerFirst(Object e):將指定的元素插入該雙向隊列的開頭。
(7)boolean offerLast(Object e):將指定的元素插入該雙向隊列的尾部。
(8)Object peekFirst():獲取、但不刪除該雙向隊列的第一個元素;若是此雙向隊列爲空,則返回null。
(9)Object peekLast():獲取、但不刪除該雙向隊列的最後一個元素;若是此雙向隊列爲空,則返回null。
(10)Object pollFirst():獲取、並刪除該雙向隊列的第一個元素;若是此雙向隊列爲空,則返回null。
(11)Object pollLast():獲取、並刪除該雙向隊列的最後一個元素;若是此雙向隊列爲空,則返回null。
(12)Object pop():pop出該雙向隊列所表示的棧中第一個元素。
(13)void push(Object e):將一個元素push進該雙向隊列所表示的棧中。
(14)Object removeFirst():獲取、並刪除該雙向隊列的第一個元素。
(15)Object removeFirstOccurrence(Object o):刪除該雙向隊列的第一個出現元素o。
(16)removeLast():獲取、並刪除該雙向隊列的最後一個元素。
(17)removeLastOccurrence(Object o):刪除該雙向隊列的最後一次出現元素o。
總結:LinkedList與ArrayList、Vector的實現機制徹底不一樣。ArrayList、Vector內部以數組的形式來保存集合中的元素,所以隨機訪問集合元素上有較好的性能;而linkedList內部以鏈表的形式來保存集合中的元素,所以隨機方法集合元素時性能較差,但在插入、刪除元素時性能很是出色(只需改變指針所指的地址便可)。
PriorityQueue實現類
PriorityQueue是一個比較標準的隊列實現類,PriorityQueue保存隊列元素的順序並非按加入隊列的順序,而是按隊列元素的大小進行從新排序。
PriorityQueue不容許插入null元素,它須要對隊列元素進行排序。
排序的方式:天然排序,定製排序。
上面是對List集合的詳解總結。在開發過程當中,咱們可能只運用到一些常見的結合,但其餘集合也應作相應的瞭解。