遍歷 vs. 查找
遍歷和修改似乎是一對矛盾,一個可以高效率插入刪除元素的數(shù)據(jù)結構通常遍歷的性能并不是最優(yōu)。于是
JCF在這里根據(jù)用戶的目標實現(xiàn)了兩種定制的數(shù)據(jù)結構:
哈希表(包括HashSet和HashMap)和平衡二叉樹(包括TreeSet和
TreeMap)。
由于可排序性是一種獨特的要求,所以引入了SortedSet和SortedMap,它們分別是AbstractSet和
AbstractMap的子接口,而TreeSet和TreeMap又分別是他們的一種實現(xiàn)。熟悉數(shù)據(jù)結構的人可能比較了解,哈希表在進行插入、刪除、查
找這樣的操作是很快的,其時間復雜度是常數(shù)級O(1);平衡二叉樹雖然插入、刪除操作比較麻煩(需要O(log
n)的代價),但進行遍歷和排序卻很快。選擇完全在于用戶的側重點,但由于類型轉換的方便性,通常我們用哈希表構造一個集合以后,再把它轉換成相應的樹集
進行遍歷,以獲得較好的效果。
歷史實現(xiàn) vs. 新實現(xiàn)
歷史實現(xiàn)(Legacy
Implementations)是JCF的一個術語,準確的意義不是很清楚,但大致可以認為在Java 2(JDK
1.2)出現(xiàn)以前的老版本中JCF的一個雛形框架。在Java
2以后,JCF才開始完善健壯起來,新實現(xiàn)中出現(xiàn)了一些新的類用于替代老版本中的成員,但由于種種原因,老版本中很多類都代表了傳統(tǒng)數(shù)據(jù)結構的精髓部分,
以及一些安全原因,所以仍然被我們使用著。
Enumeration vs. Iterator
Enumeration是一個傳統(tǒng)的集合遍歷工具,在新的JCF中使用的是Iterator,Iterator同樣具有遍歷功能,還包含一個remove()方法來刪除當前得到的元素。
Dictionary vs. Map
Dictionary
是一個現(xiàn)在已經(jīng)被標記為deprecated的類,實現(xiàn)了老版本中的映射功能,現(xiàn)在已經(jīng)完全被Map取代。它們的區(qū)別是:Dictionary中key和
value不能為null,但Map卻允許空的關鍵字和值,這一點直接影響到它們的后代:Hashtable和HashMap。
Vector vs. ArrayList
Vector
和ArrayList是數(shù)組在JCF中的體現(xiàn),還記得前面講過的數(shù)組的缺點么?Vector和ArrayList就是一種可以動態(tài)增長的數(shù)組。
Vector是歷史實現(xiàn),它和ArrayList的主要區(qū)別在于,Vector是同步集合(或者說是線程安全的),但ArrayList并不是同步的,由
于同步需要花一定的代價,所以ArrayList看起來要比Vector的存取訪問效率更高。關于同步我們下面還將要談到。
Hashtable vs. HashMap
Hashtable
是Dictionary的子類,屬于歷史實現(xiàn),而HashMap是Map的子類,是新實現(xiàn)。它們的區(qū)別除了上面所說的key和value是否可以為空之
外,也有同步的差別,Hashtable是同步的,但HashMap不是。HashMap的一個經(jīng)典的例子就是JSP的內(nèi)置對象session。不過不要
因為Hashtable是“老前輩”而瞧不起它哦,它的一個著名的子類Properties我們可是經(jīng)常會用到的。
同步 vs. 不同步
從上面的描述中我們似乎可以得出這么一個印象:歷史實現(xiàn)好像都是同步的,但新實現(xiàn)中卻
沒有。需要同步操作的理由是,可能存在多個線程對同一個集合進行操作的情況:譬如一個線程正在對某集合進行遍歷,但與此同時,另一個線程又在對該集合進行
插入或刪除,那么第一個線程的遍歷結果將是不可預測的,對于同步集合,它將會拋出一個ConcurrentModificationException異常,JCF把這種機制成為“fail-fast”。我們對比一下Vector和ArrayList的源代碼就可以發(fā)現(xiàn)Vector的很多方法都是有synchronized關鍵字修飾的,但ArrayList沒有。
容易遺忘的工具:Collections和Arrays
在圖1中右下角落里有兩個類叫做Collections(注意,不是
Collection!)和Arrays,這是JCF里面功能強大的工具,但初學者往往會忽視。按JCF文檔的說法,這兩個類提供了封裝器實現(xiàn)
(Wrapper Implementations)、數(shù)據(jù)結構算法和數(shù)組相關的應用。
想必大家不會忘記上面談到的“折半查找”、“排序”等經(jīng)典算法吧,Collections類提供了豐富的靜態(tài)方法幫助我們輕松完成這些在數(shù)據(jù)結構課上煩人的工作:
binarySearch:折半查找。
sort:排序,這里是一種類似于快速排序的方法,效率仍然是O(n * log n),但卻是一種穩(wěn)定的排序方法。
reverse:將線性表進行逆序操作,這個可是從前數(shù)據(jù)結構的經(jīng)典考題哦!
rotate:以某個元素為軸心將線性表“旋轉”——哇,這個功能太酷了!
swap:交換一個線性表中兩個元素的位置。
……
Collections還有一個重要功能就是“封裝器”(Wrapper),它提供了一些方法可以把一個集合轉換成一個特殊的集合:
unmodifiableXXX:轉換成只讀集合,這里XXX代表六種基本集合接口:Collection、List、Map、Set、SortedMap和SortedSet。如果你對只讀集合進行插入刪除操作,將會拋出UnsupportedOperationException異常。
synchronizedXXX:轉換成同步集合。
singleton:創(chuàng)建一個僅有一個元素的集合,這里singleton生成的是單元素Set,singletonList和singletonMap分別生成單元素的List和Map。
空集:由Collections的靜態(tài)屬性EMPTY_SET、EMPTY_LIST和EMPTY_MAP表示。
此外,我們知道把集合轉換成對象數(shù)組可以用Collection的toArray()方法,我們也可以方便地把一個對象數(shù)組轉換成一個線性表(可不要告訴我你是一個一個地add哦):Arrays.asList()。
泛型
目前我們了解的JCF的一個重要特征是:所有加入到集合當中的對象都將在表面上失去它
們自己的特性,而看上去僅僅只是一個Object對象而已,除非你把它強制類型轉換成它們原來的對象。這一點很自然,集合嘛,對象的容器,它容納的是各種
各樣的對象,而不僅僅是某種特定類型的對象。J2SE
5.0出現(xiàn)以后,JCF開始引入泛型的特性,譬如我們經(jīng)常碰到這樣的應用,就是把集合轉換成特定的數(shù)組,雖然Collection有toArray()的
方法,但可惜的是,這個數(shù)組的所有元素都是Object類型的,我們通常的做法是用一個for循環(huán)把數(shù)組的每個元素都進行強制類型轉換,雖然可行,但看上
去很笨拙,如果有了泛型,我們就可以預先指定要得到的類型,然后一次toArray就可以得到我們期望的數(shù)組,里面的元素全部都是指定類型了。慚愧的是,
我對5.0還不是太了解,具體可以參考J2SE 5.0的JCF文檔。
posted on 2009-08-14 15:18
suker 閱讀(174)
評論(0) 編輯 收藏