原文:https://blog.csdn.net/touchSea/article/details/750923
java.util包中就包含了一系列重要的集合類他宛,而對于集合類,主要需要掌握的就是它的內(nèi)部結(jié)構(gòu),以及遍歷集合的迭代模式客冈。
Collection接口
Collection是最基本的集合接口,一個(gè)Collection代表一組Object拗馒,即Collection的元素(Elements)冗茸。Collection接口的類都必須提供兩個(gè)標(biāo)準(zhǔn)的構(gòu)造函數(shù):無參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個(gè)空的Collection,有一個(gè)Collection參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個(gè)新的Collection榴捡,這個(gè)新的Collection與傳入的Collection有相同的元素杈女。后一個(gè)構(gòu)造函數(shù)允許用戶復(fù)制一個(gè)Collection。
如何遍歷Collection中的每一個(gè)元素?不論Collection的實(shí)際類型如何碧信,它都支持一個(gè)iterator()的方法赊琳,該方法返回一個(gè)迭代子,使用該迭代子即可逐一訪問Collection中每一個(gè)元素砰碴。典型的用法如下:
Iterator it = collection.iterator(); // 獲得一個(gè)迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一個(gè)元素
}
由Collection接口派生的兩個(gè)接口是List和Set躏筏。
List接口
List是有序的Collection,使用此接口能夠精確的控制每個(gè)元素插入的位置呈枉。用戶能夠使用索引來訪問List中的元素趁尼,這類似于Java的數(shù)組。和下面要提到的Set不同,List允許有相同的元素礼华。
實(shí)現(xiàn)List接口的常用類有LinkedList给猾,ArrayList,Vector和Stack芝囤。
LinkedList類
LinkedList實(shí)現(xiàn)了List接口,允許null元素辛萍。此外LinkedList提供額外的get悯姊,remove,insert方法在LinkedList的首部或尾部贩毕。這些操作使LinkedList可被用作堆棧(stack)悯许,隊(duì)列(queue)或雙向隊(duì)列(deque)。
注意LinkedList沒有同步方法辉阶。如果多個(gè)線程同時(shí)訪問一個(gè)List先壕,則必須自己實(shí)現(xiàn)訪問同步。一種解決方法是在創(chuàng)建List時(shí)構(gòu)造一個(gè)同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList類
ArrayList實(shí)現(xiàn)了可變大小的數(shù)組谆甜。它允許所有元素垃僚,包括null。ArrayList沒有同步店印。 size冈在,isEmpty,get按摘,set方法運(yùn)行時(shí)間為常數(shù)包券。但是add方法開銷為分?jǐn)偟某?shù),添加n個(gè)元素需要O(n)的時(shí)間炫贤。其他的方法運(yùn)行時(shí)間為線性溅固。
每個(gè)ArrayList實(shí)例都有一個(gè)容量(Capacity),即用于存儲(chǔ)元素的數(shù)組的大小兰珍。這個(gè)容量可隨著不斷添加新元素而自動(dòng)增加侍郭,但是增長算法并沒有定義。當(dāng)需要插入大量元素時(shí),在插入前可以調(diào)用ensureCapacity方法來增加ArrayList的容量以提高插入效率亮元。 和LinkedList一樣猛计,ArrayList也是非同步的(unsynchronized)。
Vector類
Vector非常類似ArrayList爆捞,但是Vector是同步的奉瘤。由Vector創(chuàng)建的Iterator,雖然和ArrayList創(chuàng)建的Iterator是同一接口煮甥,但是盗温,因?yàn)閂ector是同步的,當(dāng)一個(gè)Iterator被創(chuàng)建而且正在被使用成肘,另一個(gè)線程改變了Vector的狀態(tài)(例如卖局,添加或刪除了一些元素),這時(shí)調(diào)用Iterator的方法時(shí)將拋出ConcurrentModificationException双霍,因此必須捕獲該異常砚偶。
Stack 類
Stack繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的堆棧洒闸。Stack提供5個(gè)額外的方法使得Vector得以被當(dāng)作堆棧使用蟹演。基本的push和pop方法顷蟀,還有peek方法得到棧頂?shù)脑兀琫mpty方法測試堆棧是否為空骡技,search方法檢測一個(gè)元素在堆棧中的位置鸣个。Stack剛創(chuàng)建后是空棧。
Set接口
Set是一種不包含重復(fù)的元素的Collection布朦,即任意的兩個(gè)元素e1和e2都有e1.equals(e2)=false囤萤,Set最多有一個(gè)null元素。 很明顯是趴,Set的構(gòu)造函數(shù)有一個(gè)約束條件涛舍,傳入的Collection參數(shù)不能包含重復(fù)的元素。 請注意:必須小心操作可變對象(Mutable Object)唆途。如果一個(gè)Set中的可變元素改變了自身狀態(tài)導(dǎo)致Object.equals(Object)=true將導(dǎo)致一些問題富雅。
Map接口
請注意,Map沒有繼承Collection接口肛搬,Map提供key到value的映射没佑。一個(gè)Map中不能包含相同的key,每個(gè)key只能映射一個(gè)value温赔。Map接口提供3種集合的視圖蛤奢,Map的內(nèi)容可以被當(dāng)作一組key集合,一組value集合,或者一組key-value映射啤贩。
Hashtable類
Hashtable繼承Map接口待秃,實(shí)現(xiàn)一個(gè)key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value痹屹。
添加數(shù)據(jù)使用put(key, value)章郁,取出數(shù)據(jù)使用get(key),這兩個(gè)基本操作的時(shí)間開銷為常數(shù)痢掠。 Hashtable通過initial capacity和load factor兩個(gè)參數(shù)調(diào)整性能驱犹。通常缺省的load factor 0.75較好地實(shí)現(xiàn)了時(shí)間和空間的均衡。增大load factor可以節(jié)省空間但相應(yīng)的查找時(shí)間將增大足画,這會(huì)影響像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));
要取出一個(gè)數(shù),比如2央星,用相應(yīng)的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作為key的對象將通過計(jì)算其散列函數(shù)來確定與之對應(yīng)的value的位置霞怀,因此任何作為key的對象都必須實(shí)現(xiàn)hashCode和equals方法。hashCode和equals方法繼承自根類Object莉给,如果你用自定義的類當(dāng)作key的話毙石,要相當(dāng)小心,按照散列函數(shù)的定義颓遏,如果兩個(gè)對象相同徐矩,即obj1.equals(obj2)=true,則它們的hashCode必須相同叁幢,但如果兩個(gè)對象不同滤灯,則它們的hashCode不一定不同,如果兩個(gè)不同對象的hashCode相同曼玩,這種現(xiàn)象稱為沖突鳞骤,沖突會(huì)導(dǎo)致操作哈希表的時(shí)間開銷增大,所以盡量定義好的hashCode()方法黍判,能加快哈希表的操作弟孟。 如果相同的對象有不同的hashCode,對哈希表的操作會(huì)出現(xiàn)意想不到的結(jié)果(期待的get方法返回null)样悟,要避免這種問題拂募,只需要牢記一條:要同時(shí)復(fù)寫equals方法和hashCode方法庭猩,而不要只寫其中一個(gè)。 Hashtable是同步的陈症。
HashMap類
HashMap和Hashtable類似蔼水,不同之處在于HashMap是非同步的,并且允許null录肯,即null value和null key趴腋。,但是將HashMap視為Collection時(shí)(values()方法可返回Collection)论咏,其迭代子操作時(shí)間開銷和HashMap的容量成比例优炬。因此,如果迭代操作的性能相當(dāng)重要的話厅贪,不要將HashMap的初始化容量設(shè)得過高蠢护,或者load factor過低。
WeakHashMap類
WeakHashMap是一種改進(jìn)的HashMap养涮,它對key實(shí)行“弱引用”葵硕,如果一個(gè)key不再被外部所引用,那么該key可以被GC回收贯吓。
總結(jié)
如果涉及到堆棧懈凹,隊(duì)列等操作,應(yīng)該考慮用List悄谐,對于需要快速插入介评,刪除元素,應(yīng)該使用LinkedList爬舰,如果需要快速隨機(jī)訪問元素威沫,應(yīng)該使用ArrayList。
如果程序在單線程環(huán)境中洼专,或者訪問僅僅在一個(gè)線程中進(jìn)行,考慮非同步的類孵构,其效率較高屁商,如果多個(gè)線程可能同時(shí)操作一個(gè)類,應(yīng)該使用同步的類颈墅。
要特別注意對哈希表的操作蜡镶,作為key的對象要正確復(fù)寫equals和hashCode方法。
盡量返回接口而非實(shí)際的類型恤筛,如返回List而非ArrayList官还,這樣如果以后需要將ArrayList換成LinkedList時(shí),客戶端代碼不用改變毒坛。這就是針對抽象編程望伦。