經(jīng)常會(huì)看到程序中使用了記錄集,常用的有Collection、HashMap、HashSet、ArrayList,因?yàn)榉植磺宄鼈冎g的關(guān)系,所以在使用時(shí)經(jīng)常會(huì)混淆,以至于不知道從何下手。在這兒作了一個(gè)小例子,希望有助于幫大家理順?biāo)悸贰?BR>首先看一下它們的關(guān)系: Collection --List:-----------------------以特定次序存儲(chǔ)元素。所以取出來(lái)的順序可能和放入順序不同。 ---ArrayList ---LinkedList ---Vector --Set :----------------------- 不含有重復(fù)的元素 --- HashSet --- TreeSet Map ---HashMap ---HashTable ---TreeMap 補(bǔ)充: List,Set,Map將存入的數(shù)據(jù)一律視為Object類型。 Collection、List、Set、Map都是接口,不能實(shí)例化。繼承自它們的 ArrayList, Vector, HashTable,HashMap是具象class,這些才可被實(shí)例化。 vector不進(jìn)行邊界檢查。 接下來(lái)看一下具體的實(shí)例: Collection 定義一個(gè)Collection對(duì)象,指向其子類一個(gè)新創(chuàng)建的實(shí)例: Collection c = new ArrayList()此即所謂的"父類引用指向子類對(duì)象",后面只要使用c即可代表新創(chuàng)建的ArrayList。接下來(lái)給它賦值。 c.add("06S030014"); c.add("hit"); c.add("cs"); c.add("wh"); 然后如何取出來(lái)哪,實(shí)現(xiàn)了Collection接口的子類都有一個(gè)iterator()方法,通過(guò)調(diào)用該方法可以返回Iterator類型的一個(gè)對(duì)象,使用該對(duì)象即可取出所要的值。代碼如下: Iterator it=c.iterator() String s = (String)it.next(); 這只是取出其中的一條數(shù)據(jù),要想把所有的都取出來(lái),可以用循環(huán) for(Iterator it=c.iterator();it.hasNext();){ String s = (String)it.next(); }
實(shí)現(xiàn)了Collection接口的子類都可以用類似上述的方法存取數(shù)據(jù)。 HashMap HashMap不同于Collection,它的對(duì)象沒(méi)有iterator()方法,但它有一個(gè)values()方法,調(diào)用此方法后返回的是Collection對(duì)象,通過(guò)返回的對(duì)象可調(diào)用iterator()方法,從而實(shí)現(xiàn)取數(shù)據(jù)。 還有一個(gè)get()方法也可以獲得數(shù)據(jù),但只能取出單條記錄??聪旅娴睦?BR> HashMap hm1 = new HashMap(); book bk1 = new book("001","java學(xué)習(xí)","高等教育"); book bk2 = new book("002","tomcat配置","清華大學(xué)出版社"); book bk3 = new book("003","jsp","機(jī)械工業(yè)"); hm1.put("book1",bk1); hm1.put("book2",bk2); hm1.put("book3",bk3); 其中book是書籍類,有三個(gè)屬性:bookid,bookname,bookpub。具體代碼見附件。 調(diào)用put()方法將book的三個(gè)對(duì)象存入HashMap中,對(duì)應(yīng)的名字分別為book1,book2,book3 取數(shù)據(jù)的兩種方法 第一種 Iterator itt = hm1.values().iterator(); book bkex = (book) itt.next(); 取出的是第一條記錄,在此注意的是后存的先取[至于為什么我也說(shuō)不清楚] 第二種 book tempbook =(book)hm1.get("book3"); 這樣可以直接根據(jù)名字取出對(duì)應(yīng)的記錄。
以上是我得出來(lái)的一些經(jīng)驗(yàn),希望能對(duì)大家有所幫助。也歡迎大家進(jìn)一步探討! 附件是例子的完整代碼。
一下是關(guān)于線性表,鏈表,哈希表的詳細(xì)介紹,資料來(lái)源于互聯(lián)網(wǎng)。看了之后會(huì)更有助于加深對(duì)他們的了解!
線性表,鏈表,哈希表是常用的數(shù)據(jù)結(jié)構(gòu),在進(jìn)行Java開發(fā)時(shí),JDK已經(jīng)為我們提供了一系列相應(yīng)的類來(lái)實(shí)現(xiàn)基本的數(shù)據(jù)結(jié)構(gòu)。這些類均在 >java.util包中。本文試圖通過(guò)簡(jiǎn)單的描述,向讀者闡述各個(gè)類的作用以及如何正確使用這些類。 > > Collection > ├List > │├LinkedList > │├ArrayList > │└Vector > │ └Stack > └Set > Map > ├Hashtable > ├HashMap > └WeakHashMap > > Collection接口 > Collection是最基本的集合接口,一個(gè)Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元 >素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“ >子接口”如List和Set。 > 所有實(shí)現(xiàn)Collection接口的類都必須提供兩個(gè)標(biāo)準(zhǔn)的構(gòu)造函數(shù):無(wú)參數(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è)迭代子,使 >用該迭代子即可逐一訪問(wèn)Collection中每一個(gè)元素。典型的用法如下: > Iterator it = collection.iterator(); // 獲得一個(gè)迭代子 > while(it.hasNext()) { > Object obj = it.next(); // 得到下一個(gè)元素 > } > 由Collection接口派生的兩個(gè)接口是List和Set。 > > List接口 > List是有序的Collection,使用此接口能夠精確的控制每個(gè)元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數(shù)組下 >標(biāo))來(lái)訪問(wèn)List中的元素,這類似于Java的數(shù)組。 > 和下面要提到的Set不同,List允許有相同的元素。 > 除了具有Collection接口必備的iterator()方法外,List還提供一個(gè)listIterator()方法,返回一個(gè)ListIterator接口,和標(biāo)準(zhǔn)的 >Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設(shè)定元素,還能向前或向后遍歷。 > 實(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沒(méi)有同步方法。如果多個(gè)線程同時(shí)訪問(wèn)一個(gè)List,則必須自己實(shí)現(xiàn)訪問(wèn)同步。一種解決方法是在創(chuàng)建List時(shí)構(gòu)造一個(gè)同 >步的List: > List list = Collections.synchronizedList(new LinkedList(...)); > > ArrayList類 > ArrayList實(shí)現(xiàn)了可變大小的數(shù)組。它允許所有元素,包括null。ArrayList沒(méi)有同步。 > 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)增加,但是增長(zhǎng) >算法并沒(méi)有定義。當(dāng)需要插入大量元素時(shí),在插入前可以調(diào)用ensureCapacity方法來(lái)增加ArrayList的容量以提高插入效率。 > 和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。 > > Vector類 > Vector非常類似ArrayList,但是Vector是同步的。由Vector創(chuàng)建的Iterator,雖然和ArrayList創(chuàng)建的Iterator是同一接口,但是,因 >為Vector是同步的,當(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)作堆棧使用?;镜膒ush和pop方法,還 >有peek方法得到棧頂?shù)脑?,empty方法測(cè)試堆棧是否為空,search方法檢測(cè)一個(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ù)的元素。 > 請(qǐng)注意:必須小心操作可變對(duì)象(Mutable Object)。如果一個(gè)Set中的可變?cè)馗淖兞俗陨頎顟B(tài)導(dǎo)致Object.equals(Object)=true將 >導(dǎo)致一些問(wèn)題。 > > Map接口 > 請(qǐng)注意,Map沒(méi)有繼承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)的對(duì)象都可作為key或者value。 > 添加數(shù)據(jù)使用put(key, value),取出數(shù)據(jù)使用get(key),這兩個(gè)基本操作的時(shí)間開銷為常數(shù)。 > Hashtable通過(guò)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的簡(jiǎn)單示例如下,將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的對(duì)象將通過(guò)計(jì)算其散列函數(shù)來(lái)確定與之對(duì)應(yīng)的value的位置,因此任何作為key的對(duì)象都必須實(shí)現(xiàn)hashCode和equals方法。 >hashCode和equals方法繼承自根類Object,如果你用自定義的類當(dāng)作key的話,要相當(dāng)小心,按照散列函數(shù)的定義,如果兩個(gè)對(duì)象相同,即 >obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個(gè)對(duì)象不同,則它們的hashCode不一定不同,如果兩個(gè)不同對(duì)象的hashCode >相同,這種現(xiàn)象稱為沖突,沖突會(huì)導(dǎo)致操作哈希表的時(shí)間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。 > 如果相同的對(duì)象有不同的hashCode,對(duì)哈希表的操作會(huì)出現(xiàn)意想不到的結(jié)果(期待的get方法返回null),要避免這種問(wèn)題,只需要牢記 >一條:要同時(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è)得過(guò)高,或者load factor過(guò)低。 > > WeakHashMap類 > WeakHashMap是一種改進(jìn)的HashMap,它對(duì)key實(shí)行“弱引用”,如果一個(gè)key不再被外部所引用,那么該key可以被GC回收。 > > 總結(jié) > 如果涉及到堆棧,隊(duì)列等操作,應(yīng)該考慮用List,對(duì)于需要快速插入,刪除元素,應(yīng)該使用LinkedList,如果需要快速隨機(jī)訪問(wèn)元素, >應(yīng)該使用ArrayList。 > 如果程序在單線程環(huán)境中,或者訪問(wèn)僅僅在一個(gè)線程中進(jìn)行,考慮非同步的類,其效率較高,如果多個(gè)線程可能同時(shí)操作一個(gè)類,應(yīng)該 >使用同步的類。 > 要特別注意對(duì)哈希表的操作,作為key的對(duì)象要正確復(fù)寫equals和hashCode方法。 > 盡量返回接口而非實(shí)際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時(shí),客戶端代碼不用改變。 >這就是針對(duì)抽象編程 |
Collection接口,包含list和set子接口
Collection和Map接口之間的主要區(qū)別在于:Collection中存儲(chǔ)了一組對(duì)象,而Map存儲(chǔ)關(guān)鍵字/值對(duì)。
在Map對(duì)象中,每一個(gè)關(guān)鍵字最多有一個(gè)關(guān)聯(lián)的值。
Map:不能包括兩個(gè)相同的鍵,一個(gè)鍵最多能綁定一個(gè)值。null可以作為鍵,這樣的鍵只有一個(gè);可以有一個(gè)或多個(gè)鍵所對(duì)應(yīng)的
值為null。當(dāng)get()方法返回null值時(shí),即可以表示Map中沒(méi)有該鍵,也可以表示該鍵所對(duì)應(yīng)的值為null。因此,在Map中不能由get()方法來(lái)判斷Map中是否存在某個(gè)鍵,而應(yīng)該用containsKey()方法來(lái)判斷。
繼承Map的類有:HashMap,HashTable
HashMap:Map的實(shí)現(xiàn)類,缺省情況下是非同步的,可以通過(guò)Map Collections.synchronizedMap(Map m)來(lái)達(dá)到線程同步
HashTable:Dictionary的子類,確省是線程同步的。不允許關(guān)鍵字或值為null
當(dāng)元素的順序很重要時(shí)選用TreeMap,當(dāng)元素不必以特定的順序進(jìn)行存儲(chǔ)時(shí),使用HashMap。Hashtable的使用不被推薦,因?yàn)镠ashMap提供了所有類似的功能,并且速度更快。當(dāng)你需要在多線程環(huán)境下使用時(shí),HashMap也可以轉(zhuǎn)換為同步的。
以下引用: |
當(dāng)你事先不知道要存放數(shù)據(jù)的個(gè)數(shù),或者你需要一種比數(shù)組下標(biāo)存取機(jī)制更靈活的方法時(shí),你就需要用到集合類。
集合類存放于java.util包中。 集合類存放的都是對(duì)象的引用,而非對(duì)象本身,出于表達(dá)上的便利,我們稱集合中的對(duì)象就是指集合中對(duì)象的引用(reference)。 集合類型主要有3種:set(集)、list(列表)和map(映射)。
(1)集 集(set)是最簡(jiǎn)單的一種集合,它的對(duì)象不按特定方式排序,只是簡(jiǎn)單的把對(duì)象加入集合中,就像往口袋里放東西。 對(duì)集中成員的訪問(wèn)和操作是通過(guò)集中對(duì)象的引用進(jìn)行的,所以集中不能有重復(fù)對(duì)象。 集也有多種變體,可以實(shí)現(xiàn)排序等功能,如TreeSet,它把對(duì)象添加到集中的操作將變?yōu)榘凑漳撤N比較規(guī)則將其插入到有序的對(duì)象序列中。它實(shí)現(xiàn)的是SortedSet接口,也就是加入了對(duì)象比較的方法。通過(guò)對(duì)集中的對(duì)象迭代,我們可以得到一個(gè)升序的對(duì)象集合。
(2)列表 列表的主要特征是其對(duì)象以線性方式存儲(chǔ),沒(méi)有特定順序,只有一個(gè)開頭和一個(gè)結(jié)尾,當(dāng)然,它與根本沒(méi)有順序的集是不同的。 列表在數(shù)據(jù)結(jié)構(gòu)中分別表現(xiàn)為:數(shù)組和向量、鏈表、堆棧、隊(duì)列。 關(guān)于實(shí)現(xiàn)列表的集合類,是我們?nèi)粘9ぷ髦薪?jīng)常用到的,將在后邊的筆記詳細(xì)介紹。
(3)映射 映射與集或列表有明顯區(qū)別,映射中每個(gè)項(xiàng)都是成對(duì)的。映射中存儲(chǔ)的每個(gè)對(duì)象都有一個(gè)相關(guān)的關(guān)鍵字(Key)對(duì)象,關(guān)鍵字決定了對(duì)象在映射中的存儲(chǔ)位置,檢索對(duì)象時(shí)必須提供相應(yīng)的關(guān)鍵字,就像在字典中查單詞一樣。關(guān)鍵字應(yīng)該是唯一的。 關(guān)鍵字本身并不能決定對(duì)象的存儲(chǔ)位置,它需要對(duì)過(guò)一種散列(hashing)技術(shù)來(lái)處理,產(chǎn)生一個(gè)被稱作散列碼(hash code)的整數(shù)值,散列碼通常用作一個(gè)偏置量,該偏置量是相對(duì)于分配給映射的內(nèi)存區(qū)域起始位置的,由此確定關(guān)鍵字/對(duì)象對(duì)的存儲(chǔ)位置。理想情況下,散列處理應(yīng)該產(chǎn)生給定范圍內(nèi)均勻分布的值,而且每個(gè)關(guān)鍵字應(yīng)得到不同的散列碼。
java.util中共有13個(gè)類可用于管理集合對(duì)象,它們支持集、列表或映射等集合,以下是這些類的簡(jiǎn)單介紹
集: HashSet: 使用HashMap的一個(gè)集的實(shí)現(xiàn)。雖然集定義成無(wú)序,但必須存在某種方法能相當(dāng)高效地找到一個(gè)對(duì)象。使用一個(gè)HashMap對(duì)象實(shí)現(xiàn)集的存儲(chǔ)和檢索操作是在固定時(shí)間內(nèi)實(shí)現(xiàn)的. TreeSet: 在集中以升序?qū)?duì)象排序的集的實(shí)現(xiàn)。這意味著從一個(gè)TreeSet對(duì)象獲得第一個(gè)迭代器將按升序提供對(duì)象。TreeSet類使用了一個(gè)TreeMap. 列表: Vector: 實(shí)現(xiàn)一個(gè)類似數(shù)組一樣的表,自動(dòng)增加容量來(lái)容納你所需的元素。使用下標(biāo)存儲(chǔ)和檢索對(duì)象就象在一個(gè)標(biāo)準(zhǔn)的數(shù)組中一樣。你也可以用一個(gè)迭代器從一個(gè)Vector中檢索對(duì)象。Vector是唯一的同步容器類??當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問(wèn)時(shí)也是性能良好的。 Stsck: 這個(gè)類從Vector派生而來(lái),并且增加了方法實(shí)現(xiàn)棧??一種后進(jìn)先出的存儲(chǔ)結(jié)構(gòu)。 LinkedList: 實(shí)現(xiàn)一個(gè)鏈表。由這個(gè)類定義的鏈表也可以像棧或隊(duì)列一樣被使用。 ArrayList: 實(shí)現(xiàn)一個(gè)數(shù)組,它的規(guī)??勺儾⑶夷芟矜湵硪粯颖辉L問(wèn)。它提供的功能類似Vector類但不同步。 映射: HashTable: 實(shí)現(xiàn)一個(gè)映象,所有的鍵必須非空。為了能高效的工作,定義鍵的類必須實(shí)現(xiàn)hashcode()方法和equal()方法。這個(gè)類是前面java實(shí)現(xiàn)的一個(gè)繼承,并且通常能在實(shí)現(xiàn)映象的其他類中更好的使用。 HashMap: 實(shí)現(xiàn)一個(gè)映象,允許存儲(chǔ)空對(duì)象,而且允許鍵是空(由于鍵必須是唯一的,當(dāng)然只能有一個(gè))。 WeakHashMap: 實(shí)現(xiàn)這樣一個(gè)映象:通常如果一個(gè)鍵對(duì)一個(gè)對(duì)象而言不再被引用,鍵/對(duì)象對(duì)將被舍棄。這與HashMap形成對(duì)照,映象中的鍵維持鍵/對(duì)象對(duì)的生命周期,盡管使用映象的程序不再有對(duì)鍵的引用,并且因此不能檢索對(duì)象。 TreeMap: 實(shí)現(xiàn)這樣一個(gè)映象,對(duì)象是按鍵升序排列的。
Set和List都是由公共接口Collection擴(kuò)展而來(lái),所以它們都可以使用一個(gè)類型為Collection的變量來(lái)引用。這就意味著任何列表或集構(gòu)成的集合都可以用這種方式引用,只有映射類除外(但也不是完全排除在外,因?yàn)榭梢詮挠成浍@得一個(gè)列表。)所以說(shuō),把一個(gè)列表或集傳遞給方法的標(biāo)準(zhǔn)途徑是使用Collection類型的參數(shù)。 |
Java容器類Collection、List、ArrayList、Vector及map、HashTable、HashMap區(qū)別 2009-02-21 19:45 Collection是List和Set兩個(gè)接口的基接口 List在Collection之上增加了"有序" Set在Collection之上增加了"唯一" 而ArrayList是實(shí)現(xiàn)List的類...所以他是有序的. 它里邊存放的元素在排列上存在一定的先后順序 而且ArrayList是采用數(shù)組存放元素 另一種List LinkedList采用的則是鏈表。 Collection和Map接口之間的主要區(qū)別在于:Collection中存儲(chǔ)了一組對(duì)象,而Map存儲(chǔ)關(guān)鍵字/值對(duì)。 在Map對(duì)象中,每一個(gè)關(guān)鍵字最多有一個(gè)關(guān)聯(lián)的值。 Map:不能包括兩個(gè)相同的鍵,一個(gè)鍵最多能綁定一個(gè)值。null可以作為鍵,這樣的鍵只有一個(gè);可以有一個(gè)或多個(gè)鍵所對(duì)應(yīng)的 值為null。當(dāng)get()方法返回null值時(shí),即可以表示Map中沒(méi)有該鍵,也可以表示該鍵所對(duì)應(yīng)的值為null。因此,在Map中不能由get()方法來(lái)判斷Map中是否存在某個(gè)鍵,而應(yīng)該用containsKey()方法來(lái)判斷。 繼承Map的類有:HashMap,HashTable HashMap:Map的實(shí)現(xiàn)類,缺省情況下是非同步的,可以通過(guò)Map Collections.synchronizedMap(Map m)來(lái)達(dá)到線程同步 HashTable:Dictionary的子類,確省是線程同步的。不允許關(guān)鍵字或值為null 當(dāng)元素的順序很重要時(shí)選用TreeMap,當(dāng)元素不必以特定的順序進(jìn)行存儲(chǔ)時(shí),使用HashMap。Hashtable的使用不被推薦,因?yàn)镠ashMap提供了所有類似的功能,并且速度更快。當(dāng)你需要在多線程環(huán)境下使用時(shí),HashMap也可以轉(zhuǎn)換為同步的。 為什么要使用集合類當(dāng)你事先不知道要存放數(shù)據(jù)的個(gè)數(shù),或者你需要一種比數(shù)組下標(biāo)存取機(jī)制更靈活的方法時(shí),你就需要用到集合類。 理解集合類集合類存放于java.util包中。 集合類存放的都是對(duì)象的引用,而非對(duì)象本身,出于表達(dá)上的便利,我們稱集合中的對(duì)象就是指集合中對(duì)象的引用(reference)。 集合類型主要有3種:set(集)、list(列表)和map(映射)。 (1)集 集(set)是最簡(jiǎn)單的一種集合,它的對(duì)象不按特定方式排序,只是簡(jiǎn)單的把對(duì)象加入集合中,就像往口袋里放東西。 對(duì)集中成員的訪問(wèn)和操作是通過(guò)集中對(duì)象的引用進(jìn)行的,所以集中不能有重復(fù)對(duì)象。 集也有多種變體,可以實(shí)現(xiàn)排序等功能,如TreeSet,它把對(duì)象添加到集中的操作將變?yōu)榘凑漳撤N比較規(guī)則將其插入到有序的對(duì)象序列中。它實(shí)現(xiàn)的是SortedSet接口,也就是加入了對(duì)象比較的方法。通過(guò)對(duì)集中的對(duì)象迭代,我們可以得到一個(gè)升序的對(duì)象集合。 (2)列表 列表的主要特征是其對(duì)象以線性方式存儲(chǔ),沒(méi)有特定順序,只有一個(gè)開頭和一個(gè)結(jié)尾,當(dāng)然,它與根本沒(méi)有順序的集是不同的。 列表在數(shù)據(jù)結(jié)構(gòu)中分別表現(xiàn)為:數(shù)組和向量、鏈表、堆棧、隊(duì)列。 關(guān)于實(shí)現(xiàn)列表的集合類,是我們?nèi)粘9ぷ髦薪?jīng)常用到的,將在后邊的筆記詳細(xì)介紹。 (3)映射 映射與集或列表有明顯區(qū)別,映射中每個(gè)項(xiàng)都是成對(duì)的。映射中存儲(chǔ)的每個(gè)對(duì)象都有一個(gè)相關(guān)的關(guān)鍵字(Key)對(duì)象,關(guān)鍵字決定了對(duì)象在映射中的存儲(chǔ)位置,檢索對(duì)象時(shí)必須提供相應(yīng)的關(guān)鍵字,就像在字典中查單詞一樣。關(guān)鍵字應(yīng)該是唯一的。 關(guān)鍵字本身并不能決定對(duì)象的存儲(chǔ)位置,它需要對(duì)過(guò)一種散列(hashing)技術(shù)來(lái)處理,產(chǎn)生一個(gè)被稱作散列碼(hash code)的整數(shù)值,散列碼通常用作一個(gè)偏置量,該偏置量是相對(duì)于分配給映射的內(nèi)存區(qū)域起始位置的,由此確定關(guān)鍵字/對(duì)象對(duì)的存儲(chǔ)位置。理想情況下,散列處理應(yīng)該產(chǎn)生給定范圍內(nèi)均勻分布的值,而且每個(gè)關(guān)鍵字應(yīng)得到不同的散列碼。 集合類簡(jiǎn)介 java.util中共有13個(gè)類可用于管理集合對(duì)象,它們支持集、列表或映射等集合,以下是這些類的簡(jiǎn)單介紹 集: HashSet: 使用HashMap的一個(gè)集的實(shí)現(xiàn)。雖然集定義成無(wú)序,但必須存在某種方法能相當(dāng)高效地找到一個(gè)對(duì)象。使用一個(gè)HashMap對(duì)象實(shí)現(xiàn)集的存儲(chǔ)和檢索操作是在固定時(shí)間內(nèi)實(shí)現(xiàn)的. TreeSet: 在集中以升序?qū)?duì)象排序的集的實(shí)現(xiàn)。這意味著從一個(gè)TreeSet對(duì)象獲得第一個(gè)迭代器將按升序提供對(duì)象。TreeSet類使用了一個(gè)TreeMap. 列表: Vector: 實(shí)現(xiàn)一個(gè)類似數(shù)組一樣的表,自動(dòng)增加容量來(lái)容納你所需的元素。使用下標(biāo)存儲(chǔ)和檢索對(duì)象就象在一個(gè)標(biāo)準(zhǔn)的數(shù)組中一樣。你也可以用一個(gè)迭代器從一個(gè)Vector中檢索對(duì)象。Vector是唯一的同步容器類??當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問(wèn)時(shí)也是性能良好的。(同步即同時(shí)只能一個(gè)進(jìn)程訪問(wèn),其他等待) Stack: 這個(gè)類從Vector派生而來(lái),并且增加了方法實(shí)現(xiàn)棧??一種后進(jìn)先出的存儲(chǔ)結(jié)構(gòu)。 LinkedList: 實(shí)現(xiàn)一個(gè)鏈表。由這個(gè)類定義的鏈表也可以像?;蜿?duì)列一樣被使用。 ArrayList: 實(shí)現(xiàn)一個(gè)數(shù)組,它的規(guī)??勺儾⑶夷芟矜湵硪粯颖辉L問(wèn)。它提供的功能類似Vector類但不同步。 映射: HashTable: 實(shí)現(xiàn)一個(gè)映象,所有的鍵必須非空。為了能高效的工作,定義鍵的類必須實(shí)現(xiàn)hashcode()方法和equal()方法。這個(gè)類是前面java實(shí)現(xiàn)的一個(gè)繼承,并且通常能在實(shí)現(xiàn)映象的其他類中更好的使用。 HashMap: 實(shí)現(xiàn)一個(gè)映象,允許存儲(chǔ)空對(duì)象,而且允許鍵是空(由于鍵必須是唯一的,當(dāng)然只能有一個(gè))。 WeakHashMap: 實(shí)現(xiàn)這樣一個(gè)映象:通常如果一個(gè)鍵對(duì)一個(gè)對(duì)象而言不再被引用,鍵/對(duì)象對(duì)將被舍棄。這與HashMap形成對(duì)照,映象中的鍵維持鍵/對(duì)象對(duì)的生命周期,盡管使用映象的程序不再有對(duì)鍵的引用,并且因此不能檢索對(duì)象。 TreeMap: 實(shí)現(xiàn)這樣一個(gè)映象,對(duì)象是按鍵升序排列的。 下圖是集合類所實(shí)現(xiàn)的接口之間的關(guān)系: Set和List都是由公共接口Collection擴(kuò)展而來(lái),所以它們都可以使用一個(gè)類型為Collection的變量來(lái)引用。這就意味著任何列表或集構(gòu)成的集合都可以用這種方式引用,只有映射類除外(但也不是完全排除在外,因?yàn)榭梢詮挠成浍@得一個(gè)列表。)所以說(shuō),把一個(gè)列表或集傳遞給方法的標(biāo)準(zhǔn)途徑是使用Collection類型的參數(shù)。
List接口 List是有序的Collection,使用此接口能夠精確的控制每個(gè)元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數(shù)組下標(biāo))來(lái)訪問(wèn)List中的元素,這類似于Java的數(shù)組。 和下面要提到的Set不同,List允許有相同的元素。 除了具有Collection接口必備的iterator()方法外,List還提供一個(gè)listIterator()方法,返回一個(gè)ListIterator接口,和標(biāo)準(zhǔn)的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設(shè)定元素,還能向前或向后遍歷。 實(shí)現(xiàn)List接口的常用類有LinkedList,ArrayList,Vector和Stack。 ArrayList類 ArrayList實(shí)現(xiàn)了可變大小的數(shù)組。它允許所有元素,包括null。ArrayList沒(méi)有同步。 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)增加,但是增長(zhǎng)算法并沒(méi)有定義。當(dāng)需要插入大量元素時(shí),在插入前可以調(diào)用ensureCapacity方法來(lái)增加ArrayList的容量以提高插入效率。 和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。 Map接口 請(qǐng)注意,Map沒(méi)有繼承Collection接口,Map提供key到value的映射。一個(gè)Map中不能包含相同的key,每個(gè)key只能映射一個(gè)value。Map接口提供3種集合的視圖,Map的內(nèi)容可以被當(dāng)作一組key集合,一組value集合,或者一組key-value映射。 HashMap類 HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(shí)(values()方法可返回Collection),其迭代子操作時(shí)間開銷和HashMap的容量成比例。因此,如果迭代操作的性能相當(dāng)重要的話,不要將HashMap的初始化容量設(shè)得過(guò)高,或者load factor過(guò)低。 ---------------------------------------------------------------------------- 1. List是接口,List特性就是有序,會(huì)確保以一定的順序保存元素. ArrayList是它的實(shí)現(xiàn)類,是一個(gè)用數(shù)組實(shí)現(xiàn)的List. Map是接口,Map特性就是根據(jù)一個(gè)對(duì)象查找對(duì)象. HashMap是它的實(shí)現(xiàn)類,HashMap用hash表實(shí)現(xiàn)的Map,就是利用對(duì)象的hashcode(hashcode()是Object的方法)進(jìn)行快速散列查找.(關(guān)于散列查找,可以參看<<數(shù)據(jù)結(jié)構(gòu)>>) 2. 一般情況下,如果沒(méi)有必要,推薦代碼只同List,Map接口打交道. 比如:List list = new ArrayList(); 這樣做的原因是list就相當(dāng)于是一個(gè)泛型的實(shí)現(xiàn),如果想改變list的類型,只需要: List list = new LinkedList();//LinkedList也是List的實(shí)現(xiàn)類,也是ArrayList的兄弟類這樣,就不需要修改其它代碼,這就是接口編程的優(yōu)雅之處. 另外的例子就是,在類的方法中,如下聲明: private void doMyAction(List list){} 這樣這個(gè)方法能處理所有實(shí)現(xiàn)了List接口的類,一定程度上實(shí)現(xiàn)了泛型函數(shù). 3. 如果開發(fā)的時(shí)候覺(jué)得ArrayList,HashMap的性能不能滿足你的需要,可以通過(guò)實(shí)現(xiàn)List,Map(或者Collection)來(lái)定制你的自定義類