Java Collections Framework是Java提供的對集合進行定義,操作,和管理的統一的架構。這個集合框架主要由接口、抽象類、實現類構成。
Java的集合有兩大接口:Collection和Map。
Collection接口
API解釋:Collection是層次結構中的根接口。Collection 表示一組對象,這些對象也稱爲 collection 的元素。一些 collection 允許有重複的元素,而另一些則不允許。一些 collection 是有序的,而另一些則是無序的。JDK 不提供此接口的任何直接 實現:它提供更具體的子接口(如 Set 和 List,這兩個是最常用的子接口)實現。此接口通常用來傳遞 collection,並在需要最大普遍性的地方操作這些 collection。
Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)就是一個對象。
java集合只能保存引用類型的數據,是對象的引用
Java SDK不提供直接繼承自Collection的類,只提供了子接口,如Set和List。Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
所有通用的 Collection 實現類(通常通過它的一個子接口間接實現 Collection)應該提供兩個“標準”構造方法:一個是 void(無參數)構造方法,用於創建空 collection;另一個是帶有 Collection 類型單參數的構造方法,用於創建一個具有與其參數相同元素新的 collection。實際上,後者允許用戶複製任何 collection,以生成所需實現類型的一個等效 collection。儘管無法強制執行此約定(因爲接口不能包含構造方法),但是 Java 平臺庫中所有通用的 Collection 實現都遵從它。
Collection常見方法:
add(E e); addAll(Collection c);
contains(Obj o) ---- 返回是否包含指定的元素(true false) 。
containsAll(Collection c) ---- 返回是否包含c中所有元素 。
isEmpty(); iterator(); remove(); clear(); size(); toArray();
Java集合框架的基本接口/類層次結構:
[I]:接口
[C]:類
java.util.Collection [I]
+--java.util.List [I]
+--java.util.ArrayList [C]
+--java.util.LinkedList [C]
+--java.util.Vector [C]
+--java.util.Stack [C]
+--java.util.Set [I]
+--java.util.HashSet [C]
+--java.util.SortedSet [I]
+--java.util.TreeSet [C]
java.util.Map [I]
+--java.util.SortedMap [I]
+--java.util.TreeMap [C]
+--java.util.Hashtable [C]
+--java.util.HashMap [C]
+--java.util.LinkedHashMap [C]
+--java.util.WeakHashMap [C]
List子接口:
1、 可以包含重複的元素。
2、 是一個有序的集合,位置不可以改變,使用此接口能夠精確的控制每個元素插入的位置。
3、提供了按索引訪問的方式。用戶能夠使用索引(元素在List中的位置,類似於數組下標)來訪問List中的元素,這類似於Java的數組。
4
、除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向後遍歷。
實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。
LinkedList
此外LinkedList提供額外的get,remove,insert方法在
LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
List list =Collections.synchronizedList(new LinkedList(...));
ArrayList
List 接口的大小可變數組的實現。實現了所有可選列表操作,並允許包括null在內的所有元素。
每個ArrayList實例都有一個容量(Capacity),即用於存儲元素的數組的大小。這個容量可隨着不斷添加新元素而自動增加,但是增長算法 並沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
常用方法:add()
ArrayList list = new ArrayList();
List.add(“aaaaa”);
List.add(“bbbbb”);
//因爲是有序的,可以使用for循環輸出
for( ){
SOP(list);
}
利用ArrayList的toArray()返回一個對象的數組; 也可以利用Arrays.asList()方法返回一個列表
Arrays.asList()和Collection.toArray()是作爲數組和集合類的一個橋
如果想從集合類中獲得一個數組可以使用toArray()方法;如果想從數組中獲得一個列表可以使用asList()方法 :
import java.util.*;
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "x=" + x +",y=" + y;
}
}
public class ArrayListToArrayTest {
public static void main(String[] args) {
ArrayList a1 = newArrayList();
a1.add(new Point(3, 3));
a1.add(new Point(4, 4));
a1.add(new Point(5, 5));
for (int i = 0; i <a1.size(); i++) {
System.out.println(a1.get(i));
}
System.out.println(a1);
Object[] objs = a1.toArray();// 利用ArrayList的toArray()返回一個對象的數組.
for (int i = 0; i <objs.length; i++) {
System.out.println(objs[i]);
}
System.out.println(objs);//
List l =Arrays.asList(objs);// Arrays.asList()返回一個列表.
System.out.println(l);
}
}
結果:
x=3,y=3
x=4,y=4
x=5,y=5
[x=3,y=3, x=4,y=4, x=5,y=5]
x=3,y=3
x=4,y=4
x=5,y=5
[Ljava.lang.Object;@1fc4bec
[x=3,y=3, x=4,y=4, x=5,y=5]
和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。
Vector
Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和
ArrayList創建的Iterator是同一接口,但是,因爲Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了
Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出
ConcurrentModificationException,因此必須捕獲該異常。
Stack
Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop
方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否爲空,search方法檢測一個元素在堆棧中的位置。Stack剛創建後是空棧。
Set子接口:
不可以包含重複的元素。即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
Set是一個無序的集合,但是子接口SorttedSet是一個按照升序進行排列元素的Set。
很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重複的元素。
HashSet
此類實現
Set 接口,由哈希表(實際上是一個 HashMap
實例)支持。它不保證集合的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null
元素。
HashSet不是同步的,需要用以下語句來進行S同步轉換:
Set s = Collections.synchronizedSet(new HashSet(...))
SortedSet
是Set的一個子接口。TreeSet實現了SortedSet。
Set和List比較:
Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
List:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因爲會引起其他元素位置改變。
比較:
arraylist和linkedlist
1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針。
3.對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據。
這一點要看實際情況的。若只對單條數據插入或刪除,ArrayList的速度反而優於LinkedList。但若是批量隨機的插入刪除數據,LinkedList的速度大大優於ArrayList.
因爲ArrayList每插入一條數據,要移動插入點及之後的所有數據。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Map接口:
API: 將鍵映射到值的對象。一個映射不能包含重複的鍵;每個鍵最多隻能映射一個值。
Map 接口提供三種collection視圖(注意:這個collection和Collection是不同的概念,collection表示集合,Collection表示集合下的一個藉口Collection),允許以鍵集、值集合或鍵-值映射關係集的形式查看某個映射的內容。映射的順序 定義爲迭代器在映射的 collection 視圖中返回其元素的順序。某些映射實現可明確保證其順序,如 TreeMap 類;某些映射實現則不保證順序,如 HashMap 類。
Map沒有繼承Collection接口。也就是說Map和Collection是2種不同的集合。
Collection可以看作是(value)的集合,而Map可以看作是(key,value)的集合。
Map接口由Map的內容提供3種類型的集合視圖,一組key集合,一組value集合,或者一組key-value映射關係的集合。
一個Map中不能包含相同的key,每個key只能映射一個 value。
Map可以出現在k與v的映射中,v爲null的情況。
Map集合允許值對象爲null,並且沒有個數限制,所以當get()方法的返回值爲null時,可能有兩種情況,一種是在集合中沒有該鍵對象,另一種是該鍵對象沒有映射任何值對象,即值對象爲null。因此,在Map集合中不應該利用get()方法來判斷是否存在某個鍵,而應該利用containsKey()方法來判斷。
package com;
import java.util.HashMap;
import java.util.Map;
public class te {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put("k", null); // 向列表中添加數據
/**
* 使用get()判斷Map中是否包含某個鍵值對,會出現判斷不準確的情況
* */
System.out.println(map.get("kkk")); //輸出結果 null
System.out.println(map.get("k")); //輸出結果 null
/**
* 正確的做法是:containsKey()方法來判斷
* */
map.put("cc", "ggggggggggg"); // 向列表中添加數據
boolean contains = map.containsKey("cc"); //返回true或false
if (contains) {
System.out.println("在Map集合中包含鍵值對");
} else {
System.out.println("在Map集合中不包含鍵值對");
}
}
}
操作方法:
可以把這個接口方法分成三組操作:改變、查詢和提供可選視圖。
改變操作允許從映射中添加和除去鍵-值對。鍵和值都可以爲 null。但是,不能把Map 作爲一個鍵或值添加給自身。
Object put(Objectkey, Object value)返回值是被替換的值。
Objectremove(Object key)
void putAll(Mapmapping)
void clear()
查詢操作允許您檢查映射內容:
Object get(Objectkey)
booleancontainsKey(Object key)
booleancontainsValue(Object value)
int size()
boolean isEmpty()
最後一組方法允許您把鍵或值的組作爲集合來處理。
public SetkeySet()
public Collectionvalues()
public SetentrySet()
因爲映射中鍵的集合必須是唯一的,您用 Set 支持。因爲映射中值的集合可能不唯一,您用Collection 支持。最後一個方法返回一個實現 Map.Entry 接口的元素 Set。
Map.Entry 接口
Map 的 entrySet() 方法返回一個實現Map.Entry 接口的對象集合。集合中每個對象都是底層 Map 中一個特定的鍵-值對。
通過這個集合迭代,您可以獲得每一條目的鍵或值並對值進行更改。但是,如果底層 Map 在Map.Entry 接口的setValue() 方法外部被修改,此條目集就會變得無效,並導致迭代器行爲未定義。
Hashtable
Hashtable 繼承自 Dictiionary
Hashtable實現Map接口,實現一個key-value映射的哈希表。key或者value不允許爲空。
Hashtable通過initial
capacity和load factor兩個參數調整性能。通常缺省的load
factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一個數,比如2,用相應的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
-
由於作爲key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作爲key的對象都必須實現hashCode和equals方法。hashCode和equals方法繼承自根類Object。
-
如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同。如 果兩個不同對象的hashCode相同,這種現象稱爲衝突,衝突會導致操作哈希表的時間開銷增大,所以儘量定義好的hashCode()方法,能加快哈希 表的操作。
3、如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時複寫equals方法和hashCode方法,而不要只寫其中一個。
Hashtable是同步的。
HashMap
繼承了AbstractMap。
不是同步的Map。
允許null,即nullvalue和null key。
WeakHashMap
WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那麼該key可以被GC回收。
相互比較:
hashtable與hashmap
一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作爲一個表的條目的key或value
HashMap與TreeMap
1、 HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持着某種固定的順序,如果你需要得到一個有序的結果你就應該 使用TreeMap(HashMap中元素的排列順序是不固定的)。集合框架”提供兩種常規的Map實現:HashMap和TreeMap (TreeMap實現SortedMap接口)。
2、 在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現。 這個TreeMap沒有調優選項,因爲該樹總處於平衡狀態。
結過研究,二樹map一樣,但順序不一樣,導致hashCode()不一樣。
同樣做測試:
在hashMap中,同樣的值的map,順序不同,equals時,false;
而在treeMap中,同樣的值的map,順序不同,equals時,true,說明,treeMap在equals()時是整理了順序了的。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
各種情況下適合使用哪種集合:
如果涉及到堆棧,隊列等操作,應該考慮用List,對於需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,比如HashMap,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
要特別注意對哈希表的操作,作爲key的對象要正確複寫equals和hashCode方法。
儘量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以後需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如何遍歷Collection中的每一個元素?
1、增強for循環 for(Objo:c){syso(o)}
2、使用iterator , Iteratorit=c.iterator;
while(it.hasNext()){Object o = it.next()}
3、普通循環:for(Iteratorit=c.iterator();it.hasNext();){it.next() }
注意:不論Collection的實際類型如何,一般都是實現Collection接口的子接口List或者Set,而生成的實際類型。它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:
Iterator
it =collection.iterator(); // 獲得一個迭代子
while(it.hasNext()){
Object
obj =it.next(); // 得到下一個元素
}
------------------------------------------------------------------------------------------------------------------------------------------------------------
歸納總結:
接口 |
簡述 |
實現 |
操作特性 |
成員要求 |
Set |
成員不能重複 |
HashSet |
外部無序地遍歷成員 |
成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。 |
TreeSet |
外部有序地遍歷成員;附加實現了SortedSet, 支持子集等要求順序的操作 |
成員要求實現caparable接口,或者使用 Comparator構造TreeSet。成員一般爲同一類型。 |
||
LinkedHashSet |
外部按成員的插入順序遍歷成員 |
成員與HashSet成員類似 |
||
List |
提供基於索引的對成員的隨機訪問 |
ArrayList |
提供快速的基於索引的成員訪問,對尾部成員的增加和刪除支持較好 |
成員可爲任意Object子類的對象 |
LinkedList |
對列表中任何位置的成員的增加和刪除支持較好,但對基於索引的成員訪問支持性能較差 |
成員可爲任意Object子類的對象 |
||
Map |
保存鍵值對成員,基於鍵找值操作,compareTo或compare方法對鍵排序 |
HashMap |
能滿足用戶對Map的通用需求 |
鍵成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。 |
TreeMap |
支持對鍵有序地遍歷,使用時建議先用HashMap增加和刪除成員,最後從HashMap生成TreeMap;附加實現了SortedMap接口,支持子Map等要求順序的操作 |
鍵成員要求實現caparable接口,或者使用Comparator構造TreeMap。鍵成員一般爲同一類型。 |
||
LinkedHashMap |
保留鍵的插入順序,用equals 方法檢查鍵和值的相等性 |
成員可爲任意Object子類的對象,但如果覆蓋了equals方法,同時注意修改hashCode方法。 |
||
IdentityHashMap |
使用== 來檢查鍵和值的相等性。 |
成員使用的是嚴格相等 |
||
WeakHashMap |
其行爲依賴於垃圾回收線程,沒有絕對理由則少用 |
|