《list15》由會員上傳分享,免費在線閱讀,更多相關內(nèi)容在學術論文-天天文庫。
----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方第15章java.util第1部分:類集框架java.util包中包含了一些在Java2中新增加的最令人興奮的增強功能:類集。一個類集(collection)是一組對象。類集的增加使得許多java.util中的成員在結(jié)構(gòu)和體系結(jié)構(gòu)上發(fā)生根本的改變。它也擴展了包可以被應用的任務范圍。類集是被所有Java程序員緊密關注的最新型的技術。除了類集,java.util還包含了支持范圍廣泛的函數(shù)的各種各樣的類和接口。這些類和接口被核心的Java包廣泛使用,同時當然也可以被你編寫的程序所使用。對它們的應用包括產(chǎn)生偽隨機數(shù),對日期和時間的操作,觀測事件,對位集的操作以及標記字符串。由于java.util具有許多特性,因此它是Java中最被廣泛使用的一個包。java.util中包含的類如下。在Java2中新增加的一些也被列出:AbstractCollection(Java2)EventObjectRandomAbstractList(Java2)GregorianCalendarResourceBundleAbstractMap(Java2)HashMap(Java2)SimpleTimeZoneAbstractSequentialList(Java2)HashSet(Java2)StackAbstractSet(Java2)HashtableStringTokenizerArrayList(Java2)LinkedList(Java2)Timer(Java2,v1.3)Arrays(Java2)ListResourceBundleTimerTask(Java2,v1.3)BitSetLocaleTimeZoneCalendarObservableTreeMap(Java2)Collections(Java2)PropertiesTreeSet(Java2)DatePropertyPermission(Java2)VectorDictionaryPropertyResourceBundleWeakHashMap(Java2)java.util定義了如下的接口。注意其中大多數(shù)是在Java2中新增加的。Collection(Java2)List(Java2)ObserverComparator(Java2)ListIterator(Java2)Set(Java2)EnumerationMap(Java2)SortedMap(Java2)EventListenerMap.Entry(Java2)SortedSet(Java2)Iterator(Java2)ResourceBundle類,ListResourceBundle類和PropertyResourceBundle類幫助具有特定地區(qū)資源的大型程序國際化。關于這些類的討論,在這里從略。授權(quán)對系統(tǒng)屬性進行讀/寫的PropertyPermission類也超過了本書的討論范圍。EventObject和EventListener類將在第20章討論。下面將對剩下的類和接口做詳細的討論。
1----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方由于java.util包非常大,關于它的討論將分成兩章進行。本章討論那些與對象的類集有關的成員。在第16章討論其他的類和接口。15.1類集概述Java的類集(Collection)框架使你的程序處理對象組的方法標準化。在Java2出現(xiàn)之前,Java提供了一些專門的類如Dictionary,Vector,Stack和Properties去存儲和操作對象組。盡管這些類非常有用,它們卻缺少一個集中,統(tǒng)一的主題。因此例如說使用Vector的方法就會與使用Properties的方法不同。以前的專門的方法也沒有被設計成易于擴展和能適應新的環(huán)境的形式。而類集解決了這些(以及其他的一些)問題。類集框架被設計用于適應幾個目的。首先,這種框架是高性能的。對基本類集(動態(tài)數(shù)組,鏈接表,樹和散列表)的實現(xiàn)是高效率的。一般很少需要人工去對這些“數(shù)據(jù)引擎”編寫代碼(如果有的話)。第二點,框架必須允許不同類型的類集以相同的方式和高度互操作方式工作。第三點,類集必須是容易擴展和/或修改的。為了實現(xiàn)這一目標,類集框架被設計成包含一組標準的接口。對這些接口,提供了幾個標準的實現(xiàn)工具(例如LinkedList,HashSet和TreeSet),通常就是這樣使用的。如果你愿意的話,也可以實現(xiàn)你自己的類集。為了方便起見,創(chuàng)建用于各種特殊目的的實現(xiàn)工具。一部分工具可以使你自己的類集實現(xiàn)更加容易。最后,增加了允許將標準數(shù)組融合到類集框架中的機制。算法(Algorithms)是類集機制的另一個重要部分。算法操作類集,它在Collections類中被定義為靜態(tài)方法。因此它們可以被所有的類集所利用。每一個類集類不必實現(xiàn)它自己的方案,算法提供了一個處理類集的標準方法。由類集框架創(chuàng)建的另一項是Iterator接口。一個迭代程序(iterator)提供了一個多用途的,標準化的方法,用于每次訪問類集的一個元素。因此迭代程序提供了一種枚舉類集內(nèi)容(enumeratingthecontentsofacollection)的方法。因為每一個類集都實現(xiàn)Iterator,所以通過由Iterator定義的方法,任一類集類的元素都能被訪問到。因此,稍作修改,循環(huán)通過集合的程序代碼也可以被用來循環(huán)通過列表。除了類集之外,框架定義了幾個映射接口和類。映射(Maps)存儲鍵/值對。盡管映射在對項的正確使用上不是“類集”,但它們完全用類集集成。在類集框架的語言中,可以獲得映射的類集“視圖”(collection-view)。這個“視圖”包含了從存儲在類集中的映射得到的元素。因此,如果選擇了一個映射,就可以將其當做一個類集來處理。對于由java.util定義的原始類,類集機制被更新以便它們也能夠集成到新的系統(tǒng)里。所以理解下面的說法是很重要的:盡管類集的增加改變了許多原始工具類的結(jié)構(gòu),但它卻不會導致被拋棄。類集僅僅是提供了處理事情的一個更好的方法。最后的一點:如果你對C++比較熟悉的話,那么你可以發(fā)現(xiàn)Java的類集技術與在C++中定義的標準模板庫(STL)相似。在C++中叫做容器(container),而在Java中叫做類集。
2----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方15.2類集接口類集框架定義了幾個接口。本節(jié)對每一個接口都進行了概述。首先討論類集接口是因為它們決定了collection類的基本特性。不同的是,具體類僅僅是提供了標準接口的不同實現(xiàn)。支持類集的接口總結(jié)在如下的表中:接口描述Collection能使你操作對象組,它位于類集層次結(jié)構(gòu)的頂層List擴展Collection去處理序列(對象的列表)Set擴展Collection去處理集合,集合必須包含唯一元素SortedSet擴展Set去處理排序集合除了類集接口之外,類集也使用Comparator,Iterator和ListIterator接口。關于這些接口將在本章后面做更深入的描述。簡單地說,Comparator接口定義了兩個對象如何比較;Iterator和ListIterator接口枚舉類集中的對象。為了在它們的使用中提供最大的靈活性,類集接口允許對一些方法進行選擇??蛇x擇的方法使得使用者可以更改類集的內(nèi)容。支持這些方法的類集被稱為可修改的(modifiable)。不允許修改其內(nèi)容的類集被稱為不可修改的(unmodifiable)。如果對一個不可修改的類集使用這些方法,將引發(fā)一個UnsupportedOperationException異常。所有內(nèi)置的類集都是可修改的。下面討論類集接口。15.2.1類集接口Collection接口是構(gòu)造類集框架的基礎。它聲明所有類集都將擁有的核心方法。這些方法被總結(jié)在表15-1中。因為所有類集實現(xiàn)Collection,所以熟悉它的方法對于清楚地理解框架是必要的。其中幾種方法可能會引發(fā)一個UnsupportedOperationException異常。正如上面解釋的那樣,這些發(fā)生在當類集不能被修改時。當一個對象與另一個對象不兼容,例如當企圖增加一個不兼容的對象到一個類集中時。將產(chǎn)生一個ClassCastException異常。表15-1由Collection定義的方法方法描述booleanadd(Objectobj)將obj加入到調(diào)用類集中。如果obj被加入到類集中了,則返回true;如果obj已經(jīng)是類集中的一個成員或類集不能被復制時,則返回falsebooleanaddAll(Collectionc)將c中的所有元素都加入到調(diào)用類集中,如果操作成功(也就是說元素被加入了),則返回true;否則返回falsevoidclear()從調(diào)用類集中刪除所有元素
3----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方booleancontains(Objectobj)如果obj是調(diào)用類集的一個元素,則返回true,否則,返回false續(xù)表方法描述booleancontainsAll(Collectionc)如果調(diào)用類集包含了c中的所有元素,則返回true;否則,返回falsebooleanequals(Objectobj)如果調(diào)用類集與obj相等,則返回true;否則返回falseinthashCode()返回調(diào)用類集的散列碼booleanisEmpty()如果調(diào)用類集是空的,則返回true;否則返回falseIteratoriterator()返回調(diào)用類集的迭代程序Booleanremove(Objectobj)從調(diào)用類集中刪除obj的一個實例。如果這個元素被刪除了,則返回true;否則返回falseBooleanremoveAll(Collectionc)從調(diào)用類集中刪除c的所有元素。如果類集被改變了(也就是說元素被刪除了),則返回true;否則返回falseBooleanretainAll(Collectionc)刪除調(diào)用類集中除了包含在c中的元素之外的全部元素。如果類集被改變了(也就是說元素被刪除了),則返回true,否則返回falseintsize()返回調(diào)用類集中元素的個數(shù)Object[]toArray()返回一個數(shù)組,該數(shù)組包含了所有存儲在調(diào)用類集中的元素。數(shù)組元素是類集元素的拷貝Object[]toArray(Objectarray[])返回一個數(shù)組,該數(shù)組僅僅包含了那些類型與數(shù)組元素類型匹配的類集元素。數(shù)組元素是類集元素的拷貝。如果array的大小與匹配元素的個數(shù)相等,它們被返回到array。如果array的大小比匹配元素的個數(shù)小,將分配并返回一個所需大小的新數(shù)組,如果array的大小比匹配元素的個數(shù)大,在數(shù)組中,在類集元素之后的單元被置為null。如果任一類集元素的類型都不是array的子類型,則引發(fā)一個ArrayStoreException異常調(diào)用add(?)方法可以將對象加入類集。注意add(?)帶一個Object類型的參數(shù)。因為Object是所有類的超類,所以任何類型的對象可以被存儲在一個類集中。然而原始類型可能不行。例如,一個類集不能直接存儲類型int,char,double等的值。當然如果想存儲這些對象,也可以使用在第14章中介紹的原始類型包裝器之一??梢酝ㄟ^調(diào)用addAll(?)方法將一個類集的全部內(nèi)容增加到另一個類集中??梢酝ㄟ^調(diào)用remove(?)方法將一個對象刪除。為了刪除一組對象,可以調(diào)用removeAll(?)方法。調(diào)用retainAll(?)方法可以將除了一組指定的元素之外的所有元素刪除。為了清空類集,可以調(diào)用clear(?)方法。通過調(diào)用contains(?)
4----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方方法,可以確定一個類集是否包含了一個指定的對象。為了確定一個類集是否包含了另一個類集的全部元素,可以調(diào)用containsAll(?)方法。當一個類集是空的時候,可以通過調(diào)用isEmpty(?)方法來予以確認。調(diào)用size(?)方法可以獲得類集中當前元素的個數(shù)。toArray(?)方法返回一個數(shù)組,這個數(shù)組包含了存儲在調(diào)用類集中的元素。這個方法比它初看上去的能力要更重要。經(jīng)常使用類數(shù)組語法來處理類集的內(nèi)容是有優(yōu)勢的。通過在類集和數(shù)組之間提供一條路徑,可以充分利用這兩者的優(yōu)點。調(diào)用equals(?)方法可以比較兩個類集是否相等?!跋嗟取钡木_含義可以不同于從類集到類集。例如,可以執(zhí)行equals(?)方法以便用于比較存儲在類集中的元素的值,換句話說,equals(?)方法能比較對元素的引用。一個更加重要的方法是iterator(?),該方法對類集返回一個迭代程序。正如你將看到的那樣,當使用一個類集框架時,迭代程序?qū)τ诔晒Φ木幊虂碚f是至關重要的。15.2.2List接口List接口擴展了Collection并聲明存儲一系列元素的類集的特性。使用一個基于零的下標,元素可以通過它們在列表中的位置被插入和訪問。一個列表可以包含復制元素。除了由Collection定義的方法之外,List還定義了一些它自己的方法,這些方法總結(jié)在表15-2中。再次注意當類集不能被修改時,其中的幾種方法引發(fā)UnsupportedOperationException異常。當一個對象與另一個不兼容,例如當企圖將一個不兼容的對象加入一個類集中時,將產(chǎn)生ClassCastException異常。表15-2由List定義的方法方法描述voidadd(intindex,Objectobj)將obj插入調(diào)用列表,插入位置的下標由index傳遞。任何已存在的,在插入點以及插入點之后的元素將前移。因此,沒有元素被覆蓋booleanaddAll(intindex,Collectionc)將c中的所有元素插入到調(diào)用列表中,插入點的下標由index傳遞。在插入點以及插入點之后的元素將前移。因此,沒有元素被覆蓋。如果調(diào)用列表改變了,則返回true;否則返回falseObjectget(intindex)返回存儲在調(diào)用類集內(nèi)指定下標處的對象intindexOf(Objectobj)返回調(diào)用列表中obj的第一個實例的下標。如果obj不是列表中的元素,則返回-1intlastIndexOf(Objectobj)返回調(diào)用列表中obj的最后一個實例的下標。如果obj不是列表中的元素,則返回-1ListIteratorlistIterator()返回調(diào)用列表開始的迭代程序ListIteratorlistIterator(intindex)返回調(diào)用列表在指定下標處開始的迭代程序Objectremove(intindex)刪除調(diào)用列表中index位置的元素并返回刪除的元素。刪除后,列表被壓縮。也就是說,被刪除元素后面的元素的下標減一
5----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方Objectset(intindex,Objectobj)用obj對調(diào)用列表內(nèi)由index指定的位置進行賦值ListsubList(intstart,intend)返回一個列表,該列表包括了調(diào)用列表中從start到end–1的元素。返回列表中的元素也被調(diào)用對象引用對于由Collection定義的add(?)和addAll(?)方法,List增加了方法add(int,Object)和addAll(int,Collection)。這些方法在指定的下標處插入元素。由Collection定義的add(Object)和addAll(Collection)的語義也被List改變了,以便它們在列表的尾部增加元素。為了獲得在指定位置存儲的對象,可以用對象的下標調(diào)用get(?)方法。為了給類表中的一個元素賦值,可以調(diào)用set(?)方法,指定被改變的對象的下標。調(diào)用indexOf(?)或lastIndexOf(?)可以得到一個對象的下標。通過調(diào)用subList(?)方法,可以獲得列表的一個指定了開始下標和結(jié)束下標的子列表。正如你能想象到的,subList(?)方法使得列表處理十分方便。15.2.3集合接口集合接口定義了一個集合。它擴展了Collection并說明了不允許復制元素的類集的特性。因此,如果試圖將復制元素加到集合中時,add(?)方法將返回false。它本身并沒有定義任何附加的方法。15.2.4SortedSet接口SortedSet接口擴展了Set并說明了按升序排列的集合的特性。除了那些由Set定義的方法之外,由SortedSet接口說明的方法列在表15-3中。當沒有項包含在調(diào)用集合中時,其中的幾種方法引發(fā)NoSuchElementException異常。當對象與調(diào)用集合中的元素不兼容時,引發(fā)ClassCastException異常。如果試圖使用null對象,而集合不允許null時,引發(fā)NullPointerException異常。表15-3由SortedSet定義的方法方法描述Comparatorcomparator()返回調(diào)用被排序集合的比較函數(shù),如果對該集合使用自然順序,則返回nullObjectfirst()返回調(diào)用被排序集合的第一個元素SortedSetheadSet(Objectend)返回一個包含那些小于end的元素的SortedSet,那些元素包含在調(diào)用被排序集合中。返回被排序集合中的元素也被調(diào)用被排序集合所引用Objectlast()返回調(diào)用被排序集合的最后一個元素SortedSetsubSet(Objectstart,Objectend)返回一個SortedSet,它包括了從start到end–1的元素。返回類集中的元素也被調(diào)用對象所引用SortedSettailSet(Objectstart)返回一個SortedSet
6----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方,它包含了那些包含在分類集合中的大于等于start的元素。返回集合中的元素也被調(diào)用對象所引用SortedSet定義了幾種方法,使得對集合的處理更加方便。調(diào)用first(?)方法,可以獲得集合中的第一個對象。調(diào)用last(?)方法,可以獲得集合中的最后一個元素。調(diào)用subSet(?)方法,可以獲得排序集合的一個指定了第一個和最后一個對象的子集合。如果需要得到從集合的第一個元素開始的一個子集合,可以使用headSet(?)方法。如果需要獲得集合尾部的一個子集合,可以使用tailSet(?)方法。
7----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方15.3Collection類現(xiàn)在,你已經(jīng)熟悉了類集接口,下面開始討論實現(xiàn)它們的標準類。一些類提供了完整的可以被使用的工具。另一些類是抽象的,提供主框架工具,作為創(chuàng)建具體類集的起始點。沒有Collection類是同步的,但正如你將在本章后面看到的那樣,有可能獲得同步版本。標準的Collection類總結(jié)在下面的表中。類描述AbstractCollection實現(xiàn)大多數(shù)Collection接口AbstractList擴展AbstractCollection并實現(xiàn)大多數(shù)List接口AbstractSequentialList為了被類集使用而擴展AbstractList,該類集使用連續(xù)而不是隨機方式訪問其元素LinkedList通過擴展AbstractSequentialList來實現(xiàn)鏈接表ArrayList通過擴展AbstractList來實現(xiàn)動態(tài)數(shù)組AbstractSet擴展AbstractCollection并實現(xiàn)大多數(shù)Set接口HashSet為了使用散列表而擴展AbstractSetTreeSet實現(xiàn)存儲在樹中的一個集合。擴展AbstractSet注意:除了Collection類外,還有幾個從以前版本遺留下來的類,如Vector,Stack和Hashtable均被重新設計成支持類集的形式。這些內(nèi)容將在本章后面討論。下面討論具體的Collection類,舉例說明它們的用法。15.3.1ArrayList類ArrayList類擴展AbstractList并執(zhí)行List接口。ArrayList支持可隨需要而增長的動態(tài)數(shù)組。在Java中,標準數(shù)組是定長的。在數(shù)組創(chuàng)建之后,它們不能被加長或縮短,這也就意味著你必須事先知道數(shù)組可以容納多少元素。但是,你直到運行時才能知道需要多大的數(shù)組。為了解決這個問題,類集框架定義了ArrayList。本質(zhì)上,ArrayList是對象引用的一個變長數(shù)組。也就是說,ArrayList能夠動態(tài)地增加或減小其大小。數(shù)組列表以一個原始大小被創(chuàng)建。當超過了它的大小,類集自動增大。當對象被刪除后,數(shù)組就可以縮小。注意:動態(tài)數(shù)組也被從以前版本遺留下來的類Vector所支持。關于這一點,將在本章后面介紹。ArrayList有如下的構(gòu)造函數(shù):ArrayList(?)ArrayList(Collectionc)ArrayList(intcapacity)
8----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方其中第一個構(gòu)造函數(shù)建立一個空的數(shù)組列表。第二個構(gòu)造函數(shù)建立一個數(shù)組列表,該數(shù)組列表由類集c中的元素初始化。第三個構(gòu)造函數(shù)建立一個數(shù)組列表,該數(shù)組有指定的初始容量(capacity)。容量是用于存儲元素的基本數(shù)組的大小。當元素被追加到數(shù)組列表上時,容量會自動增加。下面的程序展示了ArrayList的一個簡單應用。首先創(chuàng)建一個數(shù)組列表,接著添加類型String的對象(回想一個引用字符串被轉(zhuǎn)化成一個字符串(String)對象)。接著列表被顯示出來。將其中的一些元素刪除后,再一次顯示列表。//DemonstrateArrayList.importjava.util.*;classArrayListDemo{publicstaticvoidmain(Stringargs[]){//createanarraylistArrayListal=newArrayList();System.out.println("Initialsizeofal:"+al.size());//addelementstothearraylistal.add("C");al.add("A");al.add("E");al.add("B");al.add("D");al.add("F");al.add(1,"A2");System.out.println("Sizeofalafteradditions:"+al.size());//displaythearraylistSystem.out.println("Contentsofal:"+al);//Removeelementsfromthearraylistal.remove("F");al.remove(2);System.out.println("Sizeofalafterdeletions:"+al.size());System.out.println("Contentsofal:"+al);}}該程序的輸出如下所示:Initialsizeofal:0Sizeofalafteradditions:7Contentsofal:[C,A2,A,E,B,D,F]Sizeofalafterdeletions:5Contentsofal:[C,A2,E,B,D]
9----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方注意a1開始時是空的,當添加元素后,它的大小增加了。當有元素被刪除后,它的大小又會變小。在前面的例子中,使用由toString(?)方法提供的默認的轉(zhuǎn)換顯示類集的內(nèi)容,toString(?)方法是從AbstractCollection繼承下來的。盡管它對簡短的例子程序來說是足夠了,然而很少使用這種方法去顯示實際中的類集的內(nèi)容。通常編程者會提供自己的輸出程序。但在下面的幾個例子中,仍將采用由toString(?)方法創(chuàng)建的默認輸出。盡管當對象被存儲在ArrayList對象中時,其容量會自動增加。仍可以通過調(diào)用ensureCapacity(?)方法來人工地增加ArrayList的容量。如果事先知道將在當前能夠容納的類集中存儲許許多多的項時,你可能會想這樣做。在開始時,通過一次性地增加它的容量,就能避免后面的再分配。因為再分配是很花時間的,避免不必要的處理可以改善性能。ensureCapacity(?)方法的特征如下所示:voidensureCapacity(intcap)這里,cap是新的容量。相反地,如果想要減小在ArrayList對象之下的數(shù)組的大小,以便它有正好容納當前項的大小,可以調(diào)用trimToSize(?)方法。該方法說明如下:voidtrimToSize(?)從數(shù)組列表(ArrayList)獲得數(shù)組(Array)當使用ArrayList時,有時想要獲得一個實際的數(shù)組,這個數(shù)組包含了列表的內(nèi)容。正如前面解釋的那樣,可以通過調(diào)用方法toArray(?)來實現(xiàn)它。下面是幾個為什么可能想將類集轉(zhuǎn)換成為數(shù)組的原因:·對于特定的操作,可以獲得更快的處理時間?!榱私o方法傳遞數(shù)組,而方法不必重載去接收類集?!榱藢⑿碌幕陬惣某绦蚺c不認識類集的老程序集成。無論何種原因,如下面的例子程序所示,將ArrayList轉(zhuǎn)換成數(shù)組是一件繁瑣的事情。//ConvertanArrayListintoanarray.importjava.util.*;classArrayListToArray{publicstaticvoidmain(Stringargs[]){//CreateanarraylistArrayListal=newArrayList();//Addelementstothearraylistal.add(newInteger(1));al.add(newInteger(2));al.add(newInteger(3));al.add(newInteger(4));
10----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方System.out.println("Contentsofal:"+al);//getarrayObjectia[]=al.toArray();intsum=0;//sumthearrayfor(inti=0;i 11----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方方法;為了刪除最后一個元素,可以調(diào)用removeLast(?)方法。它們的形式如下所示:ObjectremoveFirst(?)ObjectremoveLast(?)下面的程序舉例說明了幾個LinkedList支持的方法。//DemonstrateLinkedList.importjava.util.*;classLinkedListDemo{publicstaticvoidmain(Stringargs[]){//createalinkedlistLinkedListll=newLinkedList();//addelementstothelinkedlistll.add("F");ll.add("B");ll.add("D");ll.add("E");ll.add("C");ll.addLast("Z");ll.addFirst("A");ll.add(1,"A2");System.out.println("Originalcontentsofll:"+ll);//removeelementsfromthelinkedlistll.remove("F");ll.remove(2);System.out.println("Contentsofllafterdeletion:"+ll);//removefirstandlastelementsll.removeFirst();ll.removeLast();System.out.println("llafterdeletingfirstandlast:"+ll);//getandsetavalueObjectval=ll.get(2);ll.set(2,(String)val+"Changed");System.out.println("llafterchange:"+ll);}}該程序的輸出如下所示:Originalcontentsofll:[A,A2,F,B,D,E,C, 12----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方Z]Contentsofllafterdeletion:[A,A2,D,E,C,Z]llafterdeletingfirstandlast:[A2,D,E,C]llafterchange:[A2,D,EChanged,C]因為LinkedList實現(xiàn)List接口,調(diào)用add(Object)將項目追加到列表的尾部,如同addLast(?)方法所做的那樣。使用add(?)方法的add(int,Object)形式,插入項目到指定的位置,如例子程序中調(diào)用add(1,“A2”)的舉例。注意如何通過調(diào)用get(?)和set(?)方法而使得ll中的第三個元素發(fā)生了改變。為了獲得一個元素的當前值,通過get(?)方法傳遞存儲該元素的下標值。為了對這個下標位置賦一個新值,通過set(?)方法傳遞下標和對應的新值。15.3.3HashSet類HashSet擴展AbstractSet并且實現(xiàn)Set接口。它創(chuàng)建一個類集,該類集使用散列表進行存儲。正像大多數(shù)讀者很可能知道的那樣,散列表通過使用稱之為散列法的機制來存儲信息。在散列(hashing)中,一個關鍵字的信息內(nèi)容被用來確定唯一的一個值,稱為散列碼(hashcode)。而散列碼被用來當做與關鍵字相連的數(shù)據(jù)的存儲下標。關鍵字到其散列碼的轉(zhuǎn)換是自動執(zhí)行的——你看不到散列碼本身。你的程序代碼也不能直接索引散列表。散列法的優(yōu)點在于即使對于大的集合,它允許一些基本操作如add(?),contains(?),remove(?)和size(?)方法的運行時間保持不變。下面的構(gòu)造函數(shù)定義為:HashSet(?)HashSet(Collectionc)HashSet(intcapacity)HashSet(intcapacity,floatfillRatio)第一種形式構(gòu)造一個默認的散列集合。第二種形式用c中的元素初始化散列集合。第三種形式用capacity初始化散列集合的容量。第四種形式用它的參數(shù)初始化散列集合的容量和填充比(也稱為加載容量)。填充比必須介于0.0與1.0之間,它決定在散列集合向上調(diào)整大小之前,有多少能被充滿。具體的說,就是當元素的個數(shù)大于散列集合容量乘以它的填充比時,散列集合被擴大。對于沒有獲得填充比的構(gòu)造函數(shù),默認使用0.75。HashSet沒有定義任何超過它的超類和接口提供的其他方法。重要的是,注意散列集合并沒有確保其元素的順序,因為散列法的處理通常不讓自己參與創(chuàng)建排序集合。如果需要排序存儲,另一種類集——TreeSet將是一個更好的選擇。這里是一個說明HashSet的例子。//DemonstrateHashSet.importjava.util.*;classHashSetDemo{publicstaticvoidmain(Stringargs[]){//createahashsetHashSeths=newHashSet(); 13----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方//addelementstothehashseths.add("B");hs.add("A");hs.add("D");hs.add("E");hs.add("C");hs.add("F");System.out.println(hs);}}下面是該程序的輸出:[A,F,E,D,C,B]如上面解釋的那樣,元素并沒有按順序進行存儲。15.3.4TreeSet類TreeSet為使用樹來進行存儲的Set接口提供了一個工具,對象按升序存儲。訪問和檢索是很快的。在存儲了大量的需要進行快速檢索的排序信息的情況下,TreeSet是一個很好的選擇。下面的構(gòu)造函數(shù)定義為:TreeSet(?)TreeSet(Collectionc)TreeSet(Comparatorcomp)TreeSet(SortedSetss)第一種形式構(gòu)造一個空的樹集合,該樹集合將根據(jù)其元素的自然順序按升序排序。第二種形式構(gòu)造一個包含了c的元素的樹集合。第三種形式構(gòu)造一個空的樹集合,它按照由comp指定的比較函數(shù)進行排序(比較函數(shù)將在本章后面介紹)。第四種形式構(gòu)造一個包含了ss的元素的樹集合這里是一個說明TreeSet的例子。//DemonstrateTreeSet.importjava.util.*;classTreeSetDemo{publicstaticvoidmain(Stringargs[]){//CreateatreesetTreeSetts=newTreeSet();//Addelementstothetreesetts.add("C");ts.add("A");ts.add("B");ts.add("E");ts.add("F"); 14----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方ts.add("D");System.out.println(ts);}}這個程序的輸出如下所示:[A,B,C,D,E,F]正如上面解釋的那樣,因為TreeSet按樹存儲其元素,它們被按照排序次序自動安排,如程序輸出所示。15.4通過迭代函數(shù)訪問類集通常希望循環(huán)通過類集中的元素。例如,可能會希望顯示每一個元素。到目前為止,處理這個問題的最簡單方法是使用iterator,iterator是一個或者實現(xiàn)Iterator或者實現(xiàn)ListIterator接口的對象。Iterator可以完成循環(huán)通過類集,從而獲得或刪除元素。ListIterator擴展Iterator,允許雙向遍歷列表,并可以修改單元。Iterator接口說明的方法總結(jié)在表15-4中。ListIterator接口說明的方法總結(jié)在表15-5中。表15-4由Iterator定義的方法方法描述booleanhasNext()如果存在更多的元素,則返回true,否則返回falseObjectnext()返回下一個元素。如果沒有下一個元素,則引發(fā)NoSuchElementException異常voidremove()刪除當前元素,如果試圖在調(diào)用next()方法之后,調(diào)用remove()方法,則引發(fā)IllegalStateException異常表15-5由ListIterator定義的方法方法描述voidadd(Objectobj)將obj插入列表中的一個元素之前,該元素在下一次調(diào)用next()方法時,被返回booleanhasNext()如果存在下一個元素,則返回true;否則返回falsebooleanhasPrevious()如果存在前一個元素,則返回true;否則返回falseObjectnext()返回下一個元素,如果不存在下一個元素,則引發(fā)一個NoSuchElementException異常intnextIndex()返回下一個元素的下標,如果不存在下一個元素,則返回列表的大小Objectprevious()返回前一個元素,如果前一個元素不存在,則引發(fā)一個NoSuchElementException異常intpreviousIndex()返回前一個元素的下標,如果前一個元素不存在,則返回-1voidremove()從列表中刪除當前元素。如果remove()方法在next()方法或previous() 15----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方方法調(diào)用之前被調(diào)用,則引發(fā)一個IllegalStateException異常voidset(Objectobj)將obj賦給當前元素。這是上一次調(diào)用next()方法或previous()方法最后返回的元素15.4.1使用迭代函數(shù)在通過迭代函數(shù)訪問類集之前,必須得到一個迭代函數(shù)。每一個Collection類都提供一個iterator(?)函數(shù),該函數(shù)返回一個對類集頭的迭代函數(shù)。通過使用這個迭代函數(shù)對象,可以訪問類集中的每一個元素,一次一個元素。通常,使用迭代函數(shù)循環(huán)通過類集的內(nèi)容,步驟如下:1.通過調(diào)用類集的iterator(?)方法獲得對類集頭的迭代函數(shù)。2.建立一個調(diào)用hasNext(?)方法的循環(huán),只要hasNext(?)返回true,就進行循環(huán)迭代。3.在循環(huán)內(nèi)部,通過調(diào)用next(?)方法來得到每一個元素。對于執(zhí)行List的類集,也可以通過調(diào)用ListIterator來獲得迭代函數(shù)。正如上面解釋的那樣,列表迭代函數(shù)提供了前向或后向訪問類集的能力,并可讓你修改元素。否則,ListIterator如同Iterator功能一樣。這里是一個實現(xiàn)這些步驟的例子,說明了Iterator和ListIterator。它使用ArrayList對象,但是總的原則適用于任何類型的類集。當然,ListIterator只適用于那些實現(xiàn)List接口的類集。//Demonstrateiterators.importjava.util.*;classIteratorDemo{publicstaticvoidmain(Stringargs[]){//createanarraylistArrayListal=newArrayList();//addelementstothearraylistal.add("C");al.add("A");al.add("E");al.add("B");al.add("D");al.add("F");//useiteratortodisplaycontentsofalSystem.out.print("Originalcontentsofal:");Iteratoritr=al.iterator();while(itr.hasNext()){Objectelement=itr.next();System.out.print(element+"");}System.out.println();//modifyobjectsbeingiterated 16----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方ListIteratorlitr=al.listIterator();while(litr.hasNext()){Objectelement=litr.next();litr.set(element+"+");}System.out.print("Modifiedcontentsofal:");itr=al.iterator();while(itr.hasNext()){Objectelement=itr.next();System.out.print(element+"");}System.out.println();//now,displaythelistbackwardsSystem.out.print("Modifiedlistbackwards:");while(litr.hasPrevious()){Objectelement=litr.previous();System.out.print(element+"");}System.out.println();}}程序的輸出如下所示:Originalcontentsofal:CAEBDFModifiedcontentsofal:C+A+E+B+D+F+Modifiedlistbackwards:F+D+B+E+A+C+特別值得注意的是:列表是如何被反向顯示的。在列表被修改之后,litr指向列表的末端(記住,當?shù)竭_列表末端時,litr.hasNext(?)方法返回false)。為了以反向遍歷列表,程序繼續(xù)使用litr,但這一次,程序檢測它是否有前一個元素。只要它有前一個元素,該元素就被獲得并被顯示出來。15.5將用戶定義的類存儲于Collection中為了簡單,前面的例子在類集中存儲內(nèi)置的對象,如String或Integer。當然,類集并沒有被限制為只能存儲內(nèi)置的對象。完全相反的是,類集的能力是它能存儲任何類型的對象,包括你所創(chuàng)建的類的對象。例如,考慮下面的例子,在這個例子中使用LinkedList存儲信箱地址。//Asimplemailinglistexample.importjava.util.*;classAddress{privateStringname;privateStringstreet;privateStringcity; 17----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方privateStringstate;privateStringcode;Address(Stringn,Strings,Stringc,Stringst,Stringcd){name=n;street=s;city=c;state=st;code=cd;}publicStringtoString(){returnname+" 18"+street+" 19"+city+""+state+""+code;}}classMailList{publicstaticvoidmain(Stringargs[]){LinkedListml=newLinkedList();//addelementstothelinkedlistml.add(newAddress("J.W.West","11OakAve","Urbana","IL","61801"));ml.add(newAddress("RalphBaker","1142MapleLane","Mahomet","IL","61853"));ml.add(newAddress("TomCarlton","867ElmSt","Champaign","IL","61820"));Iteratoritr=ml.iterator();while(itr.hasNext()){Objectelement=itr.next();System.out.println(element+" 20");}System.out.println();}}程序的輸出如下所示:J.W.West11OakAveUrbanaIL61801RalphBaker1142MapleLaneMahometIL61853TomCarlton867ElmStChampaignIL61820 21----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方除了在類集中存儲用戶定義的類之外,關于上面程序的另一個重要的,值得注意的事情是它是非常短的。當考慮用50行代碼建立一個能夠?qū)崿F(xiàn)存儲,檢索,以及處理信箱地址的鏈表時,類集框架的能力就變得顯而易見了。正如大多數(shù)讀者知道的那樣,如果所有這些功能都必須用人工編寫代碼的話,程序?qū)⒈痊F(xiàn)在的長好幾倍。類集對許多不同的編程問題提供了現(xiàn)成的解決方案。每當情況出現(xiàn)時,就可以用它們。15.6處理映射正如在本章開始時所談到的,除了類集,Java2還在java.util中增加了映射。映射(map)是一個存儲關鍵字和值的關聯(lián)或者說是關鍵字/值對的對象。給定一個關鍵字,可以得到它的值。關鍵字和值都是對象。關鍵字必須是唯一的。但值是可以被復制的。有些映射可以接收null關鍵字和null值。而有的則不行。15.6.1映射接口因為映射接口定義了映射的特征和本質(zhì),因此關于映射的討論從這里開始。下面的接口支持映射:接口描述Map映射唯一關鍵字給值Map.Entry描述映射中的元素(關鍵字/值對)。這是Map的一個內(nèi)部類SortedMap擴展Map以便關鍵字按升序保持下面對每個接口依次進行討論。Map接口Map接口映射唯一關鍵字到值。關鍵字(key)是以后用于檢索值的對象。給定一個關鍵字和一個值,可以存儲這個值到一個Map對象中。當這個值被存儲以后,就可以使用它的關鍵字來檢索它。由Map說明的方法總結(jié)在表15-6中。當調(diào)用的映射中沒有項存在時,其中的幾種方法會引發(fā)一個NoSuchElementException異常。而當對象與映射中的元素不兼容時,引發(fā)一個ClassCastException異常。如果試圖使用映射不允許使用的null對象時,則引發(fā)一個NullPointerException異常。當試圖改變一個不允許修改的映射時,則引發(fā)一個UnsupportedOperationException異常。表15-6由Map定義的方法方法描述voidclear()從調(diào)用映射中刪除所有的關鍵字/值對booleancontainsKey(Objectk)如果調(diào)用映射中包含了作為關鍵字的k,則返回true;否則返回false 22----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方booleancontainsValue(Objectv)如果映射中包含了作為值的v,則返回true;否則返回falseSetentrySet()返回包含了映射中的項的集合(Set)。該集合包含了類型Map.Entry的對象。這個方法為調(diào)用映射提供了一個集合“視圖”Booleanequals(Objectobj)如果obj是一個Map并包含相同的輸入,則返回true;否則返回falseObjectget(Objectk)返回與關鍵字k相關聯(lián)的值inthashCode()返回調(diào)用映射的散列碼booleanisEmpty()如果調(diào)用映射是空的,則返回true;否則返回falseSetkeySet()返回一個包含調(diào)用映射中關鍵字的集合(Set)。這個方法為調(diào)用映射的關鍵字提供了一個集合“視圖”O(jiān)bjectput(Objectk,Objectv)將一個輸入加入調(diào)用映射,覆蓋原先與該關鍵字相關聯(lián)的值。關鍵字和值分別為k和v。如果關鍵字已經(jīng)不存在了,則返回null;否則,返回原先與關鍵字相關聯(lián)的值voidputAll(Mapm)將所有來自m的輸入加入調(diào)用映射Objectremove(Objectk)刪除關鍵字等于k的輸入續(xù)表方法描述intsize()返回映射中關鍵字/值對的個數(shù)Collectionvalues()返回一個包含了映射中的值的類集。這個方法為映射中的值提供了一個類集“視圖”映射循環(huán)使用兩個基本操作:get(?)和put(?)。使用put(?)方法可以將一個指定了關鍵字和值的值加入映射。為了得到值,可以通過將關鍵字作為參數(shù)來調(diào)用get(?)方法。調(diào)用返回該值。正如前面談到的,映射不是類集,但可以獲得映射的類集“視圖”。為了實現(xiàn)這種功能,可以使用entrySet(?)方法,它返回一個包含了映射中元素的集合(Set)。為了得到關鍵字的類集“視圖”,可以使用keySet(?)方法。為了得到值的類集“視圖”,可以使用values(?)方法。類集“視圖”是將映射集成到類集框架內(nèi)的手段。SortedMap接口SortedMap接口擴展了Map,它確保了各項按關鍵字升序排序。由SortedMap說明的方法總結(jié)在表15-7中。當調(diào)用映射中沒有的項時,其中的幾種方法引發(fā)一個NoSuchElementException異常。當對象與映射中的元素不兼容時,則引發(fā)一個ClassCastException異常。當試圖使用映射不允許使用的null對象時,則引發(fā)一個NullPointerException異常。表15-7由SortedMap定義的方法方法描述Comparatorcomparator() 23----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方返回調(diào)用排序映射的比較函數(shù)。如果調(diào)用映射使用的是自然順序的話,則返回nullObjectfirstKey()返回調(diào)用映射的第一個關鍵字SortedMapheadMap(Objectend)返回一個排序映射,該映射包含了那些關鍵字小于end的映射輸入ObjectlastKey()返回調(diào)用映射的最后一個關鍵字SortedMapsubMap(Objectstart,Objectend)返回一個映射,該映射包含了那些關鍵字大于等于start同時小于end的輸入SortedMaptailMap(Objectstart)返回一個映射,該映射包含了那些關鍵字大于等于start的輸入排序映射允許對子映射(換句話說,就是映射的子集)進行高效的處理。使用headMap(?),tailMap(?)或subMap(?)方法可以獲得子映射。調(diào)用firstKey(?)方法可以獲得集合的第一個關鍵字。而調(diào)用lastKey(?)方法可以獲得集合的最后一個關鍵字。Map.Entry接口Map.Entry接口使得可以操作映射的輸入。回想由Map接口說明的entrySet(?)方法,調(diào)用該方法返回一個包含映射輸入的集合(Set)。這些集合元素的每一個都是一個Map.Entry對象。表15-8總結(jié)了由該接口說明的方法。表15-8由Map.Entry定義的方法方法描述booleanequals(Objectobj)如果obj是一個關鍵字和值都與調(diào)用對象相等的Map.Entry,則返回trueObjectgetKey()返回該映射項的關鍵字ObjectgetValue()返回該映射項的值inthashCode()返回該映射項的散列值ObjectsetValue(Objectv)將這個映射輸入的值賦給v。如果v不是映射的正確類型,則引發(fā)一個ClassCastException異常。如果v存在問題,則引發(fā)一個IllegalArgumentException異常。如果v是null而映射又不允許null關鍵字,則引發(fā)一個NullPointerException異常。如果映射不能被改變,則引發(fā)一個UnsupportedOperationException異常。15.6.2映射類有幾個類提供了映射接口的實現(xiàn)??梢员挥米鲇成涞念惪偨Y(jié)如下:類描述AbstractMap實現(xiàn)大多數(shù)的Map接口HashMap將AbstractMap擴展到使用散列表TreeMap將AbstractMap擴展到使用樹 24----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方WeakHashMap將AbstractMap擴展到使用弱關鍵字散列表注意AbstractMap對三個具體的映射實現(xiàn)來說,是一個超類。WeakHashMap實現(xiàn)一個使用“弱關鍵字”的映射,它允許映射中的元素,當該映射的關鍵字不再被使用時,被放入回收站。關于這個類,在這里不做更深入的討論。其他的類將在下面介紹。HashMap類HashMap類使用散列表實現(xiàn)Map接口。這允許一些基本操作如get(?)和put(?)的運行時間保持恒定,即便對大型集合,也是這樣的。下面的構(gòu)造函數(shù)定義為:HashMap(?)HashMap(Mapm)HashMap(intcapacity)HashMap(intcapacity,floatfillRatio)第一種形式構(gòu)造一個默認的散列映射。第二種形式用m的元素初始化散列映射。第三種形式將散列映射的容量初始化為capacity。第四種形式用它的參數(shù)同時初始化散列映射的容量和填充比。容量和填充比的含義與前面介紹的HashSet中的容量和填充比相同。HashMap實現(xiàn)Map并擴展AbstractMap。它本身并沒有增加任何新的方法。應該注意的是散列映射并不保證它的元素的順序。因此,元素加入散列映射的順序并不一定是它們被迭代函數(shù)讀出的順序。下面的程序舉例說明了HashMap。它將名字映射到賬目資產(chǎn)平衡表。注意集合“視圖”是如何獲得和被使用的。importjava.util.*;classHashMapDemo{publicstaticvoidmain(Stringargs[]){//CreateahashmapHashMaphm=newHashMap();//Putelementstothemaphm.put("JohnDoe",newDouble(3434.34));hm.put("TomSmith",newDouble(123.22));hm.put("JaneBaker",newDouble(1378.00));hm.put("ToddHall",newDouble(99.22));hm.put("RalphSmith",newDouble(-19.08));//GetasetoftheentriesSetset=hm.entrySet();//GetaniteratorIteratori=set.iterator();//Displayelements 25----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方while(i.hasNext()){Map.Entryme=(Map.Entry)i.next();System.out.print(me.getKey()+":");System.out.println(me.getValue());}System.out.println();//Deposit1000intoJohnDoe'saccountdoublebalance=((Double)hm.get("JohnDoe")).doubleValue();hm.put("JohnDoe",newDouble(balance+1000));System.out.println("JohnDoe'snewbalance:"+hm.get("JohnDoe"));}}該程序的輸出如下所示:ToddHall:99.22RalphSmith:-19.08JohnDoe:3434.34JaneBaker:1378.0TomSmith:123.22JohnDoe’scurrentbalance:4434.34程序開始創(chuàng)建一個散列映射,然后將名字的映射增加到平衡表中。接下來,映射的內(nèi)容通過使用由調(diào)用函數(shù)entrySet(?)而獲得的集合“視圖”而顯示出來。關鍵字和值通過調(diào)用由Map.Entry定義的getKey(?)和getValue(?)方法而顯示。注意存款是如何被制成JohnDoe的賬目的。put(?)方法自動用新值替換與指定關鍵字相關聯(lián)的原先的值。因此,在JohnDoe的賬目被更新后,散列映射將仍然僅僅保留一個“JohnDoe”賬目。TreeMap類TreeMap類通過使用樹實現(xiàn)Map接口。TreeMap提供了按排序順序存儲關鍵字/值對的有效手段,同時允許快速檢索。應該注意的是,不像散列映射,樹映射保證它的元素按照關鍵字升序排序。下面的TreeMap構(gòu)造函數(shù)定義為:TreeMap(?)TreeMap(Comparatorcomp)TreeMap(Mapm)TreeMap(SortedMapsm)第一種形式構(gòu)造一個空樹的映射,該映射使用其關鍵字的自然順序來排序。第二種形式構(gòu)造一個空的基于樹的映射,該映射通過使用Comparatorcomp來排序(比較函數(shù)Comparators將在本章后面進行討論)。第三種形式用從m的輸入初始化樹映射,該映射使用關鍵字的自然順序來排序。第四種形式用從sm的輸入來初始化一個樹映射,該映射將按與sm相同的順序來排序。 26----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方TreeMap實現(xiàn)SortedMap并且擴展AbstractMap。而它本身并沒有另外定義其他方法。下面的程序重新使前面的例子運轉(zhuǎn),以便在其中使用TreeMap:importjava.util.*;classTreeMapDemo{publicstaticvoidmain(Stringargs[]){//CreateatreemapTreeMaptm=newTreeMap();//Putelementstothemaptm.put("JohnDoe",newDouble(3434.34));tm.put("TomSmith",newDouble(123.22));tm.put("JaneBaker",newDouble(1378.00));tm.put("ToddHall",newDouble(99.22));tm.put("RalphSmith",newDouble(-19.08));//GetasetoftheentriesSetset=tm.entrySet();//GetaniteratorIteratori=set.iterator();//Displayelementswhile(i.hasNext()){Map.Entryme=(Map.Entry)i.next();System.out.print(me.getKey()+":");System.out.println(me.getValue());}System.out.println();//Deposit1000intoJohnDoe'saccountdoublebalance=((Double)tm.get("JohnDoe")).doubleValue();tm.put("JohnDoe",newDouble(balance+1000));System.out.println("JohnDoe'snewbalance:"+tm.get("JohnDoe"));}}下面是該程序的輸出結(jié)果:JaneBaker:1378.0JohnDoe:3434.34RalphSmith:-19.08ToddHall:99.22TomSmith:123.22JohnDoe’scurrentbalance:4434.34注意對關鍵字進行了排序。然而,在這種情況下,它們用名字而不是用姓進行了排序??梢酝ㄟ^在創(chuàng)建映射時,指定一個比較函數(shù)來改變這種排序。在下一節(jié)將介紹如何做。 27----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方15.7比較函數(shù)TreeSet和TreeMap都按排序順序存儲元素。然而,精確定義采用何種“排序順序”的是比較函數(shù)。通常在默認的情況下,這些類通過使用被Java稱之為“自然順序”的順序存儲它們的元素,而這種順序通常也是你所需要的(A在B的前面,1在2的前面,等等)。如果需要用不同的方法對元素進行排序,可以在構(gòu)造集合或映射時,指定一個Comparator對象。這樣做為你提供了一種精確控制如何將元素儲存到排序類集和映射中的能力。Comparator接口定義了兩個方法:compare(?)和equals(?)。這里給出的compare(?)方法按順序比較了兩個元素:intcompare(Objectobj1,Objectobj2)obj1和obj2是被比較的兩個對象。當兩個對象相等時,該方法返回0;當obj1大于obj2時,返回一個正值;否則,返回一個負值。如果用于比較的對象的類型不兼容的話,該方法引發(fā)一個ClassCastException異常。通過覆蓋compare(?),可以改變對象排序的方式。例如,通過創(chuàng)建一個顛倒比較輸出的比較函數(shù),可以實現(xiàn)按逆向排序。這里給出的equals(?)方法,測試一個對象是否與調(diào)用比較函數(shù)相等:booleanequals(Objectobj)obj是被用來進行相等測試的對象。如果obj和調(diào)用對象都是Comparator的對象并且使用相同的排序。該方法返回true。否則返回false。重載equals(?)方法是沒有必要的,大多數(shù)簡單的比較函數(shù)都不這樣做。15.7.1使用比較函數(shù)下面是一個說明定制的比較函數(shù)能力的例子。該例子實現(xiàn)compare(?)方法以便它按正常順序的逆向進行操作。因此,它使得一個樹集合按逆向的順序進行存儲。//Useacustomcomparator.importjava.util.*;//Areversecomparatorforstrings.classMyCompimplementsComparator{publicintcompare(Objecta,Objectb){StringaStr,bStr;aStr=(String)a;bStr=(String)b;//reversethecomparisonreturnbStr.compareTo(aStr);}//noneedtooverride 28----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方equals}classCompDemo{publicstaticvoidmain(Stringargs[]){//CreateatreesetTreeSetts=newTreeSet(newMyComp());//Addelementstothetreesetts.add("C");ts.add("A");ts.add("B");ts.add("E");ts.add("F");ts.add("D");//GetaniteratorIteratori=ts.iterator();//Displayelementswhile(i.hasNext()){Objectelement=i.next();System.out.print(element+"");}System.out.println();}}正如下面的輸出所示,樹按照逆向順序進行存儲:FEDCBA仔細觀察實現(xiàn)Comparator并覆蓋compare(?)方法的MyComp類(正如前面所解釋的那樣,覆蓋equals(?)方法既不是必須的,也不是常用的)。在compare(?)方法內(nèi)部,String方法compareTo(?)比較兩個字符串。然而由bStr——不是aStr——調(diào)用compareTo(?)方法,這導致比較的結(jié)果被逆向。對應一個更實際的例子,下面的例子是用TreeMap程序?qū)崿F(xiàn)前面介紹的存儲賬目資產(chǎn)平衡表例子的程序。在前面介紹的程序中,賬目是按名進行排序的,但程序是以按照名字進行排序開始的。下面的程序按姓對賬目進行排序。為了實現(xiàn)這種功能,程序使用了比較函數(shù)來比較每一個賬目下姓的排序。得到的映射是按姓進行排序的。//Useacomparatortosortaccountsbylastname.importjava.util.*;//Comparelastwholewordsintwostrings.classTCompimplementsComparator{publicintcompare(Objecta,Objectb){inti,j,k;StringaStr,bStr;aStr=(String)a;bStr=(String)b; 29----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方//findindexofbeginningoflastnamei=aStr.lastIndexOf('');j=bStr.lastIndexOf('');k=aStr.substring(i).compareTo(bStr.substring(j));if(k==0)//lastnamesmatch,checkentirenamereturnaStr.compareTo(bStr);elsereturnk;}//noneedtooverrideequals}classTreeMapDemo2{publicstaticvoidmain(Stringargs[]){//CreateatreemapTreeMaptm=newTreeMap(newTComp());//Putelementstothemaptm.put("JohnDoe",newDouble(3434.34));tm.put("TomSmith",newDouble(123.22));tm.put("JaneBaker",newDouble(1378.00));tm.put("ToddHall",newDouble(99.22));tm.put("RalphSmith",newDouble(-19.08));//GetasetoftheentriesSetset=tm.entrySet();//GetaniteratorIteratoritr=set.iterator();//Displayelementswhile(itr.hasNext()){Map.Entryme=(Map.Entry)itr.next();System.out.print(me.getKey()+":");System.out.println(me.getValue());}System.out.println();//Deposit1000intoJohnDoe'saccountdoublebalance=((Double)tm.get("JohnDoe")).doubleValue();tm.put("JohnDoe",newDouble(balance+1000));System.out.println("JohnDoe'snewbalance:"+tm.get("JohnDoe"));}}這里是程序的輸出結(jié)果,注意此時的賬目是按姓進行排序的:JaneBaker:1378.0JohnDoe:3434.34ToddHall:99.22RalphSmith: 30----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方-19.08TomSmith:123.22JohnDoe’snewbalance:4434.34比較函數(shù)類TComp比較兩個包含姓和名的字符串。它首先比較姓。具體是這樣做的,它首先尋找每一個字符串中最后一個空格的下標,然后比較從這個位置開始的每一個元素的子字符串。當兩個字符串中姓完全相等時,它再比較兩個名。這樣就形成了一個先按姓進行排序,在姓相同的情況下,再按名字進行排序的樹型映射。通過程序的輸出中RalphSmith出現(xiàn)在TomSmith之前的結(jié)果可以看到這一點。15.8類集算法類集框架定義了幾種能用于類集和映射的算法。在Collections類中,這些算法被定義為靜態(tài)方法。表15-9中列出了這些算法。當試圖比較不兼容的類型時,其中的一些算法引發(fā)一個ClassCastException異常;而當試圖改變一個不可改變的類集時,則引發(fā)一個UnsupportedOperationException異常。表15-9由Collections定義的算法方法描述staticintbinarySearch(Listlist,Objectvalue,Comparatorc)按照c的次序在list中搜尋value。如果value在list內(nèi),則返回value在list的位置。如果在list中沒有發(fā)現(xiàn)value,則返回-1staticintbinarySearch(Listlist,Objectvalue)在list中搜尋value,列表(list)必須被排序。如果value在list內(nèi),則返回value的位置。如果在list中沒有發(fā)現(xiàn)value,則返回-1staticvoidcopy(Listlist1,Listlist2)將list2中的元素復制給list1續(xù)表方法描述staticEnumerationenumeration(Collectionc)返回c的一個枚舉(參看本章后面的“枚舉接口”)。staticvoidfill(Listlist,Objectobj)將obj賦給list中的每一個元素StaticObjectmax(Collectionc,Comparatorcomp)返回由comp確定的c中的最大元素staticObjectmax(Collectionc)返回按自然順序確定的c中的最大元素。類集不必被排序staticObjectmin(Collectionc,Comparatorcomp)返回由comp確定的c中的最小元素。類集不必被排序staticObjectmin(Collectionc)返回按自然順序確定的c中的最小元素staticListnCopies(intnum,Objectobj)返回包含在不可改變的列表中的obj的num個拷貝。num必須大于等于0staticvoidreverse(Listlist)將list中的序列逆向 31----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方staticComparatorreverseOrder()返回一個逆向比較函數(shù)(即將兩個元素比較的結(jié)果進行逆向的比較函數(shù))staticvoidshuffle(Listlist,Randomr)用r作為隨機數(shù)的源,對list中的元素進行混淆(也即隨機化)staticvoidshuffle(Listlist)對list中的元素進行混淆(也即隨機化)staticSetsingleton(Objectobj)返回一個不可改變的集合obj。這是一個實現(xiàn)將單個對象變成集合的簡單辦法staticListsingletonList(Objectobj)返回一個不可改變的列表obj。這是一個實現(xiàn)將單個對象變成列表的簡單辦法(在Java2的1.3版中新增加的)staticMapsingletonMap(Objectk,Objectv)返回一個不可改變的關鍵字/值對映射k/v。這是一個實現(xiàn)將單個關鍵字/值對變成映射的簡單辦法(在Java2的1.3版中新增加的)staticvoidsort(Listlist,Comparatorcomp)按comp對list中的元素進行排序staticvoidsort(Listlist)按自然順序?qū)ist中的元素進行排序staticCollectionsynchronizedCollection(Collectionc)返回一個被c支持的安全線程類集staticListsynchronizedList(Listlist)返回一個被list支持的安全線程列表staticMapsynchronizedMap(Mapm)返回一個被m支持的安全線程映射staticSetsynchronizedSet(Sets)返回一個被s支持的安全線程集合staticSortedMapsynchronizedSortedMap(SortedMapsm)返回一個被sm支持的安全線程排序集合staticSortedSetsynchronizedSortedSet(SortedSetss)返回一個被ss支持的安全線程集合staticCollectionunmodifiableCollection(Collectionc)返回一個被c支持的不可變類集StaticListunmodifiableList(Listlist)返回一個被list支持的不可變列表續(xù)表方法描述staticMapunmodifiableMap(Mapm)返回一個被m支持的不可變映射staticSetunmodifiableSet(Sets)返回一個被s支持的不可變集合StaticSortedMapunmodifiableSortedMap(SortedMapsm)返回一個被sm支持的不可變排序映射staticSortedSetunmodifiableSortedSet(SortedSetss)返回一個被ss支持的不可變排序集合注意其中的幾種方法,如synchronizedList(?)和synchronizedSet(?)被用來獲得各種類集的同步(安全線程)拷貝。正如前面解釋的那樣,沒有任何一個標準類集實現(xiàn)是同步的。必須使用同步算法來為其提供同步。另一種觀點:同步類集的迭代函數(shù)必須在synchronized 32----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方塊內(nèi)使用。以unmodifiable開頭的一組方法返回不能被改變的各種類集“視圖”。這些方法當將一些進程對類集設為只讀形式時很有用的。Collections定義了三個靜態(tài)變量:EMPTY_SET,EMPTY_LIST和EMPTY_MAP。它們都是不可改變的。EMPTY_MAP是在Java2的1.3版中新增加的。下面的程序說明了其中的一些算法。該程序創(chuàng)建和初始化了一個鏈表。reverseOrder(?)方法返回一個對Integer對象的比較進行逆向的Comparator函數(shù)。列表中的元素按照這個比較函數(shù)進行排序并被顯示出來。接下來,調(diào)用shuffle(?)方法對列表進行隨機排列。然后顯示列表的最大和最小值。//Demonstratevariousalgorithms.importjava.util.*;classAlgorithmsDemo{publicstaticvoidmain(Stringargs[]){//CreateandinitializelinkedlistLinkedListll=newLinkedList();ll.add(newInteger(-8));ll.add(newInteger(20));ll.add(newInteger(-20));ll.add(newInteger(8));//CreateareverseordercomparatorComparatorr=Collections.reverseOrder();//SortlistbyusingthecomparatorCollections.sort(ll,r);//GetiteratorIteratorli=ll.iterator();System.out.print("Listsortedinreverse:");while(li.hasNext())System.out.print(li.next()+"");System.out.println();Collections.shuffle(ll);//displayrandomizedlistli=ll.iterator();System.out.print("Listshuffled:");while(li.hasNext())System.out.print(li.next()+"");System.out.println();System.out.println("Minimum:"+Collections.min(ll));System.out.println("Maximum:"+Collections.max(ll)); 33----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方}}該程序的輸出如下所示:Listsortedinreverse:208-8-20Listshuffled:20-208-8Minimum:-20Maximum:20注意min(?)和max(?)方法是在列表被混淆之后,對其進行操作的。兩者在運行時,都不需要排序的列表。15.9Arrays(數(shù)組)Java2在java.util中新增加了一個叫做Arrays的類。這個類提供了各種在進行數(shù)組運算時很有用的方法。盡管這些方法在技術上不屬于類集框架,但它們提供了跨越類集和數(shù)組的橋梁。在這一節(jié)中,分析由Arrays定義的每一種方法。asList(?)方法返回一個被指定數(shù)組支持的List。換句話說,列表和數(shù)組訪問的是同一個單元。它具有如下的形式:staticListasList(Object[]array)這里array是包含了數(shù)據(jù)的數(shù)組。binarySearch(?)方法使用二進制搜索尋找指定的值。該方法必須應用于排序數(shù)組。它具有如下的形式:staticintbinarySearch(byte[]array,bytevalue)staticintbinarySearch(char[]array,charvalue)staticintbinarySearch(double[]array,doublevalue)staticintbinarySearch(float[]array,floatvalue)staticintbinarySearch(int[]array,intvalue)staticintbinarySearch(long[]array,longvalue)staticintbinarySearch(short[]array,shortvalue)staticintbinarySearch(Object[]array,Objectvalue)staticintbinarySearch(Object[]array,Objectvalue,Comparatorc)這里,array是被搜索的數(shù)組,而value是被查找的值。當array中包含的元素是不可比較的(例如Double和StringBuffer)或者當value與array中的類型不兼容時,后兩種形式引發(fā)一個ClassCastException異常。在最后一種形式中,比較函數(shù)(Comparator)c用于確定array中的元素的順序。在所有的形式中,如果array中含有value,則返回該元素的下標。否則,返回一個負值。當兩個數(shù)組相等時,equals(?)方法返回true;否則返回false。equals(?)方法具有下面的一些形式:staticbooleanequals(booleanarray1[],booleanarray2[])staticbooleanequals(bytearray1[],bytearray2[ 34----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方])staticbooleanequals(chararray1[],chararray2[])staticbooleanequals(doublearray1[],doublearray2[])staticbooleanequals(floatarray1[],floatarray2[])staticbooleanequals(intarray1[],intarray2[])staticbooleanequals(longarray1[],longarray2[])staticbooleanequals(shortarray1[],shortarray2[])staticbooleanequals(Objectarray1[],Objectarray2[])這里array1和array2是兩個用來比較看是否相等的數(shù)組。fill(?)方法將一個值賦給數(shù)組中的所有元素。換句話說,它用一個指定的值填充數(shù)組。fill(?)方法有兩種形式。第一種形式具有下面的一些形式,填充整個數(shù)組:staticvoidfill(booleanarray[],booleanvalue)staticvoidfill(bytearray[],bytevalue)staticvoidfill(chararray[],charvalue)staticvoidfill(doublearray[],doublevalue)staticvoidfill(floatarray[],floatvalue)staticvoidfill(intarray[],intvalue)staticvoidfill(longarray[],longvalue)staticvoidfill(shortarray[],shortvalue)staticvoidfill(Objectarray[],Objectvalue)這里value被賦給數(shù)組array中的每一個元素。fill(?)方法的第二種形式將一個值賦給數(shù)組的一個子集。它的幾種形式如下:staticvoidfill(booleanarray[],intstart,intend,booleanvalue)staticvoidfill(bytearray[],intstart,intend,bytevalue)staticvoidfill(chararray[],intstart,intend,charvalue)staticvoidfill(doublearray[],intstart,intend,doublevalue)staticvoidfill(floatarray[],intstart,intend,floatvalue)staticvoidfill(intarray[],intstart,intend,intvalue)staticvoidfill(longarray[],intstart,intend,longvalue)staticvoidfill(shortarray[],intstart,intend,shortvalue)staticvoidfill(Objectarray[],intstart,intend,Objectvalue)這里,value是賦給數(shù)組array中從start開始到end–1結(jié)束的子集的值。這些方法當start大于end時,都能引發(fā)一個IllegalArgumentException異常;而當start或end出界時,都能引發(fā)一個ArrayIndexOutOfBoundsException異常。sort(?)方法對數(shù)組進行排序,以便數(shù)組能夠按升序進行排列。sort(?)方法有兩種形式。下面給出的第一種形式對整個數(shù)組進行排序:staticvoidsort(bytearray[])staticvoidsort(chararray[])staticvoidsort(doublearray[])staticvoidsort(floatarray[])staticvoidsort(intarray[])staticvoidsort(longarray[])staticvoidsort(shortarray[])staticvoidsort(Objectarray[])staticvoidsort(Objectarray[],Comparatorc) 35----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方這里,array是被排序的數(shù)組。在最后的一種形式中,c是一個用來規(guī)定array中元素順序的比較函數(shù)(Comparator)。當用于排序的數(shù)組中的元素不可比較時,這些對Object的數(shù)組進行排序的sort(?)方法將引發(fā)一個ClassCastException異常。sort(?)方法的第二種形式允許在一個數(shù)組內(nèi),指定一個想要進行排序的范圍。它的具體形式如下:staticvoidsort(bytearray[],intstart,intend)staticvoidsort(chararray[],intstart,intend)staticvoidsort(doublearray[],intstart,intend)staticvoidsort(floatarray[],intstart,intend)staticvoidsort(intarray[],intstart,intend)staticvoidsort(longarray[],intstart,intend)staticvoidsort(shortarray[],intstart,intend)staticvoidsort(Objectarray[],intstart,intend)staticvoidsort(Objectarray[],intstart,intend,Comparatorc)這里,數(shù)組中想要進行排序的范圍從start到end–1。在最后一種形式中,c是一個用來規(guī)定array中元素順序的Comparator。如果start大于end,所有這些方法都能引發(fā)一個IllegalArgumentException異常;而當start或end出界時,又都能引發(fā)一個ArrayIndexOutOfBoundsException異常。當用于排序的數(shù)組中的元素不可比較時,最后兩種形式也能引發(fā)一個ClassCastException異常。下面的程序舉例說明了如何使用Arrays類中的一些方法://DemonstrateArraysimportjava.util.*;classArraysDemo{publicstaticvoidmain(Stringargs[]){//allocateandinitializearrayintarray[]=newint[10];for(inti=0;i<10;i++)array[i]=-3*i;//display,sort,displaySystem.out.print("Originalcontents:");display(array);Arrays.sort(array);System.out.print("Sorted:");display(array);//fillanddisplayArrays.fill(array,2,6,-1);System.out.print("Afterfill():");display(array);//sortanddisplayArrays.sort(array);System.out.print("Aftersortingagain:"); 36----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方display(array);//binarysearchfor-9System.out.print("Thevalue-9isatlocation");intindex=Arrays.binarySearch(array,-9);System.out.println(index);}staticvoiddisplay(intarray[]){for(inti=0;i 37----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方接口定義了可以對一個對象的類集中的元素進行枚舉(一次獲得一個)的方法。這個接口盡管沒有被擯棄,但已經(jīng)被Iterator所替代。Enumeration對新程序來說是過時的。然而它仍被幾種從以前版本遺留下來的類(例如Vector和Properties)所定義的方法使用,被幾種其他的API類所使用以及被目前廣泛使用的應用程序所使用。Enumeration指定下面的兩個方法:booleanhasMoreElements(?)ObjectnextElement(?)執(zhí)行后,當仍有更多的元素可提取時,hasMoreElements(?)方法一定返回true。當所有元素都被枚舉了,則返回false。nextElement(?)方法將枚舉中的下一個對象做為一個類屬Object的引用而返回。也就是每次調(diào)用nextElement(?)方法獲得枚舉中的下一個對象。調(diào)用例程必須將那個對象置為包含在枚舉內(nèi)的對象類型。15.10.2VectorVector實現(xiàn)動態(tài)數(shù)組。這與ArrayList相似,但兩者不同的是:Vector是同步的,并且它包含了許多不屬于類集框架的從以前版本遺留下來的方法。隨著Java2的公布,Vector被重新設計來擴展AbstractList和實現(xiàn)List接口,因此現(xiàn)在它與類集是完全兼容的。這里是Vector的構(gòu)造函數(shù):Vector(?)Vector(intsize)Vector(intsize,intincr)Vector(Collectionc)第一種形式創(chuàng)建一個原始大小為10的默認矢量。第二種形式創(chuàng)建一個其原始容量由size指定的矢量。第三種形式創(chuàng)建一個其原始容量由size指定,并且它的增量由incr指定的矢量。增量指定了矢量每次允許向上改變大小的元素的個數(shù)。第四種形式創(chuàng)建一個包含了類集c中元素的矢量。這個構(gòu)造函數(shù)是在Java2中新增加的。所有的矢量開始都有一個原始的容量。在這個原始容量達到以后,下一次再試圖向矢量中存儲對象時,矢量自動為那個對象分配空間同時為別的對象增加額外的空間。通過分配超過需要的內(nèi)存,矢量減小了可能產(chǎn)生的分配的次數(shù)。這種次數(shù)的減少是很重要的,因為分配內(nèi)存是很花時間的。在每次再分配中,分配的額外空間的總數(shù)由在創(chuàng)建矢量時指定的增量來確定。如果沒有指定增量,在每個分配周期,矢量的大小增一倍。Vector定義了下面的保護數(shù)據(jù)成員:intcapacityIncrement;intelementCount;ObjectelementData[];增量值被存儲在capacityIncrement中。矢量中的當前元素的個數(shù)被存儲在elementCount中。保存矢量的數(shù)組被存儲在elementData中。除了由List定義的類集方法之外,Vector還定義了幾個從以前版本遺留下來的方法,這些方法列在表15-10中。 38----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方表15-10由Vector定義的方法方法描述finalvoidaddElement(Objectelement)將由element指定的對象加入矢量intcapacity()返回矢量的容量Objectclone()返回調(diào)用矢量的一個拷貝Booleancontains(Objectelement)如果element被包含在矢量中,則返回true;如果不包含于其中,則返回falsevoidcopyInto(Objectarray[])將包含在調(diào)用矢量中的元素復制到由array指定的數(shù)組中ObjectelementAt(intindex)返回由index指定位置的元素Enumerationelements()返回矢量中元素的一個枚舉ObjectfirstElement()返回矢量的第一個元素intindexOf(Objectelement)返回element首次出現(xiàn)的位置下標。如果對象不在矢量中,則返回-1intindexOf(Objectelement,intstart)返回element在矢量中在start及其之后第一次出現(xiàn)的位置下標。如果該對象不屬于矢量的這一部分,則返回-1voidinsertElementAt(Objectelement,intindex)在矢量中,在由index指定的位置處加入elementbooleanisEmpty()如果矢量是空的,則返回true。如果它包含了一個或更多個元素,則返回falseObjectlastElement()返回矢量中的最后一個元素intlastIndexOf(Objectelement)返回element在矢量中最后一次出現(xiàn)的位置下標。如果對象不包含在矢量中,則返回-1intlastIndexOf(Objectelement,intstart)返回element在矢量中,在start之前最后一次出現(xiàn)的位置下標。如果該對象不屬于矢量的這一部分,則返回-1voidremoveAllElements()清空矢量,在這個方法執(zhí)行以后,矢量的大小為0booleanremoveElement(Objectelement)從矢量中刪除element。對于指定的對象,矢量中如果有其多個實例,則其中第一個實例被刪除。如果成功刪除,則返回true;如果沒有發(fā)現(xiàn)對象,則返回falsevoidremoveElementAt(intindex)刪除由index指定位置處的元素voidsetElementAt(Objectelement,intindex)將由index指定的位置分配給elementvoidsetSize(intsize)將矢量中元素的個數(shù)設為size。如果新的長度小于老的長度,元素將丟失;如果新的長度大于老的長度,則在其后增加null元素intsize()返回矢量中當前元素的個數(shù)續(xù)表方法描述StringtoString()返回矢量的字符串等價形式 39----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方voidtrimToSize()將矢量的容量設為與其當前擁有的元素的個數(shù)相等因為Vector實現(xiàn)List,所以可以像使用ArrayList的一個實例那樣使用矢量。也可以使用它的從以前版本遺留下來的方法來操作它。例如,在后面實例化Vector,可以通過調(diào)用addElement(?)方法而為其增加一個元素。調(diào)用elementAt(?)方法可以獲得指定位置處的元素。調(diào)用firstElement(?)方法可以得到矢量的第一個元素。調(diào)用lastElement(?)方法可以檢索到矢量的最后一個元素。使用indexOf(?)和lastIndexOf(?)方法可以獲得元素的下標。調(diào)用removeElement(?)或removeElementAt(?)方法可以刪除元素。下面的程序使用矢量存儲不同類型的數(shù)值對象。程序說明了幾種由Vector定義的從以前版本遺留下來的方法,同時它也說明了枚舉(Enumeration)接口。//DemonstratevariousVectoroperations.importjava.util.*;classVectorDemo{publicstaticvoidmain(Stringargs[]){//initialsizeis3,incrementis2Vectorv=newVector(3,2);System.out.println("Initialsize:"+v.size());System.out.println("Initialcapacity:"+v.capacity());v.addElement(newInteger(1));v.addElement(newInteger(2));v.addElement(newInteger(3));v.addElement(newInteger(4));System.out.println("Capacityafterfouradditions:"+v.capacity());v.addElement(newDouble(5.45));System.out.println("Currentcapacity:"+v.capacity());v.addElement(newDouble(6.08));v.addElement(newInteger(7));System.out.println("Currentcapacity:"+v.capacity());v.addElement(newFloat(9.4));v.addElement(newInteger(10));System.out.println("Currentcapacity:"+v.capacity());v.addElement(newInteger(11));v.addElement(newInteger(12));System.out.println("Firstelement:"+(Integer)v.firstElement()); 40----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方System.out.println("Lastelement:"+(Integer)v.lastElement());if(v.contains(newInteger(3)))System.out.println("Vectorcontains3.");//enumeratetheelementsinthevector.EnumerationvEnum=v.elements();System.out.println(" 41Elementsinvector:");while(vEnum.hasMoreElements())System.out.print(vEnum.nextElement()+"");System.out.println();}}該程序的輸出如下所示:Initialsize:0Initialcapacity:3Capacityafterfouradditions:5Currentcapacity:5Currentcapacity:7Currentcapacity:9Firstelement:1Lastelement:12Vectorcontains3.Elementsinvector:12345.456.0879.4101112隨著Java2的公布,Vector增加了對迭代函數(shù)的支持?,F(xiàn)在可以使用迭代函數(shù)來替代枚舉去遍歷對象(正如前面的程序所做的那樣)。例如,下面的基于迭代函數(shù)的程序代碼可以被替換到上面的程序中://useaniteratortodisplaycontentsIteratorvItr=v.iterator();System.out.println(" 42Elementsinvector:");while(vItr.hasNext())System.out.print(vItr.next()+"");System.out.println();因為建議不要使編寫枚舉新的程序代碼,所以通??梢允褂玫瘮?shù)來對矢量的內(nèi)容進行枚舉。當然,業(yè)已存在的大量的老程序采用了枚舉。不過幸運的是,枚舉和迭代函數(shù)的工作方式幾乎相同。15.10.3StackStack是Vector的一個子類,它實現(xiàn)標準的后進先出堆棧。Stack僅僅定義了創(chuàng)建空堆棧的默認構(gòu)造函數(shù)。Stack包括了由Vector 43----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方定義的所有方法,同時增加了幾種它自己定義的方法,具體總結(jié)在表15-11中。表15-11由Stack定義的方法方法描述booleanempty()如果堆棧是空的,則返回true,當堆棧包含有元素時,返回falseObjectpeek()返回位于棧頂?shù)脑?,但是并不在堆棧中刪除它Objectpop()返回位于棧頂?shù)脑?,并在進程中刪除它Objectpush(Objectelement)將element壓入堆棧,同時也返回elementintsearch(Objectelement)在堆棧中搜索element,如果發(fā)現(xiàn)了,則返回它相對于棧頂?shù)钠屏?。否則,返回-1調(diào)用push(?)方法可將一個對象壓入棧頂。調(diào)用pop(?)方法可以刪除和返回棧頂?shù)脑?。當調(diào)用堆棧是空的時,如果調(diào)用pop(?)方法,將引發(fā)一個EmptyStackException異常。調(diào)用peek(?)方法返回但不刪除棧頂?shù)膶ο蟆U{(diào)用empty(?)方法,當堆棧中沒有元素時,返回true。search(?)方法確定一個對象是否存在于堆棧,并且返回將其指向棧頂所需的彈出次數(shù)。下面是一個創(chuàng)建堆棧的例子,在例子中,將幾個整型(Integer)對象壓入堆棧,然后再將它們彈出。//DemonstratetheStackclass.importjava.util.*;classStackDemo{staticvoidshowpush(Stackst,inta){st.push(newInteger(a));System.out.println("push("+a+")");System.out.println("stack:"+st);}staticvoidshowpop(Stackst){System.out.print("pop->");Integera=(Integer)st.pop();System.out.println(a);System.out.println("stack:"+st);}publicstaticvoidmain(Stringargs[]){Stackst=newStack();System.out.println("stack:"+st);showpush(st,42);showpush(st,66);showpush(st,99);showpop(st);showpop(st);showpop(st);try{showpop(st); 44----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方}catch(EmptyStackExceptione){System.out.println("emptystack");}}}下面是由該程序產(chǎn)生的輸出。注意對于EmptyStackException的異常處理程序是如何被捕獲以便于能夠從容地處理堆棧的下溢:stack:[]push(42)stack:[42]push(66)stack:[42,66]push(99)stack:[42,66,99]pop->99stack:[42,66]pop->66stack:[42]pop->42stack:[]pop->emptystack15.10.4Dictionary字典(Dictionary)是一個表示關鍵字/值存儲庫的抽象類,同時它的操作也很像映射(Map)。給定一個關鍵字和值,可以將值存儲到字典(Dictionary)對象中。一旦這個值被存儲了,就能夠用它的關鍵字來檢索它。因此,與映射一樣,字典可以被當做關鍵字/值對列表來考慮。盡管在Java2中并沒有擯棄字典(Dictionary),由于它被映射(Map)所取代,從而被認為是過時的。然而由于目前Dictionary被廣泛地使用,因此這里仍對它進行詳細的討論。由Dictionary定義的抽象方法在表15-12中列出。表15-12由Dictionary定義的抽象方法方法描述Enumerationelements()返回對包含在字典中的值的枚舉Objectget(Objectkey)返回一個包含與key相連的值的對象。如果key不在字典中,則返回一個空對象booleanisEmpty()如果字典是空的,則返回true;如果字典中至少包含一個關鍵字,則返回falseEnumerationkeys()返回包含在字典中的關鍵字的枚舉Objectput(Objectkey,Objectvalue)將一個關鍵字和它的值插入字典中。如果key已經(jīng)不在字典中了,則返回null;如果key已經(jīng)在字典中了,則返回與key相關聯(lián)的前一個值 45----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方續(xù)表方法描述Objectremove(Objectkey)刪除key和它的值。返回與key相關聯(lián)的值。如果key不在字典中,則返回nullintsize()返回字典中的項數(shù)使用put(?)方法在字典中增加關鍵字和值。使用get(?)方法檢索給定關鍵字的值。當分別使用keys(?)和elements(?)方法進行枚舉(Enumeration)時,關鍵字和值可以分別逐個地返回。size(?)方法返回存儲在字典中的關鍵字/值對的個數(shù)。當字典是空的時候,isEmpty(?)返回true。使用remove(?)方法可以刪除關鍵字/值對。注意:Dictionary類是過時的。應該執(zhí)行Map接口去獲得關鍵字/值存儲的功能。15.10.5Hashtable散列表(Hashtable)是原始java.util中的一部分同時也是Dictionary的一個具體實現(xiàn)。然而,Java2重新設計了散列表(Hashtable)以便它也能實現(xiàn)映射(Map)接口。因此現(xiàn)在Hashtable也被集成到類集框架中。它與HashMap相似,但它是同步的。和HashMap一樣,Hashtable將關鍵字/值對存儲到散列表中。使用Hashtable時,指定一個對象作為關鍵字,同時指定與該關鍵字相關聯(lián)的值。接著該關鍵字被散列,而把得到的散列值作為存儲在表中的值的下標。散列表僅僅可以存儲重載由Object定義的hashCode(?)和equals(?)方法的對象。hashCode(?)方法計算和返回對象的散列碼。當然,equals(?)方法比較兩個對象。幸運的是,許多Java內(nèi)置的類已經(jīng)實現(xiàn)了hashCode(?)方法。例如,大多數(shù)常見的Hashtable類型使用字符串(String)對象作為關鍵字。String實現(xiàn)hashCode(?)和equals(?)方法。Hashtable的構(gòu)造函數(shù)如下所示:Hashtable(?)Hashtable(intsize)Hashtable(intsize,floatfillRatio)Hashtable(Mapm)第一種形式是默認的構(gòu)造函數(shù)。第二種形式創(chuàng)建一個散列表,該散列表具有由size指定的原始大小。第三種形式創(chuàng)建一個散列表,該散列表具有由size指定的原始大小和由fillRatio指定的填充比。填充比必須介于0.0和1.0之間,它決定了在散列表向上調(diào)整大小之前散列表的充滿度。具體地說,當元素的個數(shù)大于散列表的容量乘以它的填充比時,散列表被擴展。如果沒有指定填充比,默認使用0.75。最后,第四種形式創(chuàng)建一個散列表,該散列表用m中的元素初始化。散列表的容量被設為m中元素的個數(shù)的兩倍。默認的填充因子設為0.75。第四種構(gòu)造函數(shù)是在Java2中新增加的。除了Hashtable目前實現(xiàn)的,由Map接口定義的方法之外,Hashtable定義的從以前版本遺留下來的方法列在表15-13中。 46----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方表15-13由Hashtable定義的從以前版本遺留下來的方法方法描述voidclear()復位并清空散列表Objectclone()返回調(diào)用對象的復制booleancontains(Objectvalue)如果一些值與存在于散列表中的value相等的話,則返回true;如果這個值不存在,則返回falsebooleancontainsKey(Objectkey)如果一些關鍵字與存在于散列表中的key相等的話,則返回true;如果這個關鍵字不存在,則返回falsebooleancontainsValue(Objectvalue)如果一些值與散列表中存在的value相等的話,返回true;如果這個值沒有找到,則返回false(是一種為了保持一致性而在Java2中新增加的非Map方法)Enumerationelements()返回包含在散列表中的值的枚舉Objectget(Objectkey)返回包含與key相關聯(lián)的值的對象。如果key不在散列表中,則返回一個空對象booleanisEmpty()如果散列表是空的,則返回true;如果散列表中至少包含一個關鍵字,則返回falseEnumerationkeys()返回包含在散列表中的關鍵字的枚舉Objectput(Objectkey,Objectvalue)將關鍵字和值插入散列表中。如果key已經(jīng)不在散列表中,返回null。如果key已經(jīng)存在于散列表中,則返回與key相連的前一個值voidrehash()增大散列表的大小并且對其關鍵字進行再散列。Objectremove(Objectkey)刪除key及其對應的值。返回與key相關聯(lián)的值。如果key不在散列表中,則返回一個空對象intsize()返回散列表中的項數(shù)StringtoString()返回散列表的等價字符串形式下面的例子重寫前面介紹的關于銀行賬目的程序。在重寫的程序中,使用Hashtable儲存銀行存款人的名字和他們當前的資產(chǎn)平衡表://DemonstrateaHashtableimportjava.util.*;classHTDemo{publicstaticvoidmain(Stringargs[]){Hashtablebalance=newHashtable();Enumerationnames;Stringstr;doublebal;balance.put("JohnDoe",newDouble(3434.34)); 47----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方balance.put("TomSmith",newDouble(123.22));balance.put("JaneBaker",newDouble(1378.00));balance.put("ToddHall",newDouble(99.22));balance.put("RalphSmith",newDouble(-19.08));//Showallbalancesinhashtable.names=balance.keys();while(names.hasMoreElements()){str=(String)names.nextElement();System.out.println(str+":"+balance.get(str));}System.out.println();//Deposit1,000intoJohnDoe'saccountbal=((Double)balance.get("JohnDoe")).doubleValue();balance.put("JohnDoe",newDouble(bal+1000));System.out.println("JohnDoe'snewbalance:"+balance.get("JohnDoe"));}}該程序的輸出如下所示:ToddHall:99.22RalphSmith:-19.08JohnDoe:3434.34JaneBaker:1378.0TomSmith:123.22JohnDoe’snewbalance:4434.34重要的一點是:和映射類一樣,Hashtable不直接支持迭代函數(shù)。因此,上面的程序使用枚舉來顯示balance的內(nèi)容。然而,我們可以獲得允許使用迭代函數(shù)的散列表的集合視圖。為了實現(xiàn)它,可以簡單地使用由Map定義的一個類集“視圖”方法,如entrySet(?)或keySet(?)方法。例如,可以獲得關鍵字的一個集合“視圖”,并遍歷這些關鍵字。下面是采用這種技術后重新編寫的程序://UseiteratorswithaHashtable.importjava.util.*;classHTDemo2{publicstaticvoidmain(Stringargs[]){Hashtablebalance=newHashtable();Stringstr;doublebal;balance.put("JohnDoe",newDouble(3434.34));balance.put("TomSmith",newDouble(123.22));balance.put("JaneBaker",newDouble(1378.00));balance.put("ToddHall",newDouble(99.22)); 48----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方balance.put("RalphSmith",newDouble(-19.08));//showallbalancesinhashtableSetset=balance.keySet();//getset-viewofkeys//getiteratorIteratoritr=set.iterator();while(itr.hasNext()){str=(String)itr.next();System.out.println(str+":"+balance.get(str));}System.out.println();//Deposit1,000intoJohnDoe'saccountbal=((Double)balance.get("JohnDoe")).doubleValue();balance.put("JohnDoe",newDouble(bal+1000));System.out.println("JohnDoe'snewbalance:"+balance.get("JohnDoe"));}}15.10.6Properties屬性(Properties)是Hashtable的一個子類。它用來保持值的列表,在其中關鍵字和值都是字符串(String)。Properties類被許多其他的Java類所使用。例如,當獲得系統(tǒng)環(huán)境值時,System.getProperties(?)返回對象的類型。Properties定義了下面的實例變量:Propertiesdefaults;這個變量包含了一個與屬性(Properties)對象相關聯(lián)的默認屬性列表。Properties定義了如下的構(gòu)造函數(shù):Properties(?)Properties(PropertiespropDefault)第一種形式創(chuàng)建一個沒有默認值的屬性(Properties)對象。第二種形式創(chuàng)建一個將propDefault作為其默認值的對象。在這兩種情況下,屬性列表都是空的。除了Properties從Hashtable中繼承下來的方法之外,Properties自己定義的方法列在表15-14中。Properties也包含了一個不被贊成使用的方法:save(?)。它被store(?)方法所取代,因為它不能正確地處理錯誤。表15-14由Properties定義的從以前版本遺留下來的方法方法描述StringgetProperty(Stringkey)返回與key相關聯(lián)的值。如果key 49----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方既不在列表中,也不在默認屬性列表中,則返回一個null對象StringgetProperty(Stringkey,StringdefaultProperty)返回與key相關聯(lián)的值。如果key既不在列表中,也不在默認屬性列表中,則返回defaultPropertyvoidlist(PrintStreamstreamOut)將屬性列表發(fā)送給與streamOut相鏈接的輸出流voidlist(PrintWriterstreamOut)將屬性列表發(fā)送給與streamOut相鏈接的輸出流續(xù)表方法描述voidload(InputStreamstreamIn)throwsIOException從與streamIn相鏈接的輸入數(shù)據(jù)流輸入一個屬性列表EnumerationpropertyNames()返回關鍵字的枚舉,也包括那些在默認屬性列表中找到的關鍵字ObjectsetProperty(Stringkey,Stringvalue)將value與key關聯(lián)。返回與key關聯(lián)的前一個值,如果不存在這樣的關聯(lián),則返回null(為了保持一致性,在Java2中新增加的)voidstore(OutputStreamstreamOut,Stringdescription)在寫入由description指定的字符串之后,屬性列表被寫入與streamOut相鏈接的輸出流(在Java2中新增加的)Properties類的一個有用的功能是可以指定一個默認屬性,如果沒有值與特定的關鍵字相關聯(lián),則返回這個默認屬性。例如,默認值可以與關鍵字一起在getProperty(?)方法中被指定——如getProperty(“name”,“defaultvalue”)。如果“name”值沒有找到,則返回“defaultvalue”。當構(gòu)造一個Properties對象時,可以傳遞Properties的另一個實例做為新實例的默認值。在這種情況下,如果對一個給定的Properties對象調(diào)用getProperty(“foo”),而“foo”并不存在時,Java在默認Properties對象中尋找“foo”。它允許默認屬性的任意層嵌套。下面的例子說明了Properties。該程序創(chuàng)建一個屬性列表,在其中關鍵字是美國的州名,值是這些州的首府的名字。注意試圖尋找包括默認值的Florida的首府時的情況。//DemonstrateaPropertylist.importjava.util.*;classPropDemo{publicstaticvoidmain(Stringargs[]){Propertiescapitals=newProperties();Setstates;Stringstr;capitals.put("Illinois","Springfield");capitals.put("Missouri","JeffersonCity");capitals.put("Washington","Olympia");capitals.put("California","Sacramento");capitals.put("Indiana","Indianapolis");//Showallstatesandcapitalsinhashtable. 50----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方states=capitals.keySet();//getset-viewofkeysIteratoritr=states.iterator();while(itr.hasNext()){str=(String)itr.next();System.out.println("Thecapitalof"+str+"is"+capitals.getProperty(str)+".");}System.out.println();//lookforstatenotinlist--specifydefaultstr=capitals.getProperty("Florida","NotFound");System.out.println("ThecapitalofFloridais"+str+".");}}該程序的輸出如下所示:ThecapitalofMissouriisJeffersonCity.ThecapitalofIllinoisisSpringfield.ThecapitalofIndianaisIndianapolis.ThecapitalofCaliforniaisSacramento.ThecapitalofWashingtonisOlympia.ThecapitalofFloridaisNotFound.由于Florida不在列表中,所以使用了默認值。盡管當調(diào)用getProperty(?)方法時,使用默認值是十分有效的,正如上面的程序所展示的那樣,對大多數(shù)屬性列表的應用來說,有更好的方法去處理默認值。為了更大的靈活性,當構(gòu)造一個屬性(Properties)對象時,指定一個默認的屬性列表。如果在主列表中沒有發(fā)現(xiàn)期望的關鍵字,將會搜索默認列表。例如,下面是對前面程序稍作修改的程序。在該程序中,有一個指定州的默認列表。在這種情況下,當搜索Florida時,將在默認列表中找到它。//Useadefaultpropertylist.importjava.util.*;classPropDemoDef{publicstaticvoidmain(Stringargs[]){PropertiesdefList=newProperties();defList.put("Florida","Tallahassee");defList.put("Wisconsin","Madison");Propertiescapitals=newProperties(defList);Setstates;Stringstr;capitals.put("Illinois","Springfield"); 51----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方capitals.put("Missouri","JeffersonCity");capitals.put("Washington","Olympia");capitals.put("California","Sacramento");capitals.put("Indiana","Indianapolis");//Showallstatesandcapitalsinhashtable.states=capitals.keySet();//getset-viewofkeysIteratoritr=states.iterator();while(itr.hasNext()){str=(String)itr.next();System.out.println("Thecapitalof"+str+"is"+capitals.getProperty(str)+".");}System.out.println();//Floridawillnowbefoundinthedefaultlist.str=capitals.getProperty("Florida");System.out.println("ThecapitalofFloridais"+str+".");}}15.10.7使用store(?)和load(?)Properties的一個最有用的方面是可以利用store(?)和load(?)方法方便地對包含在屬性(Properties)對象中的信息進行存儲或從盤中裝入信息。在任何時候,都可以將一個屬性(Properties)對象寫入流或從中將其讀出。這使得屬性列表特別方便實現(xiàn)簡單的數(shù)據(jù)庫。例如,下面的程序使用屬性列表創(chuàng)建一個簡單的用計算機處理的存儲著姓名和電話號碼的電話本。為了尋找某人的電話號碼,可輸入他或者她的名字。程序使用store(?)和load(?)方法來存儲和檢索列表。當程序執(zhí)行時,它首先試著從一個叫做phonebook.dat的文件中裝入列表。如果這個文件存在,列表就被裝入。然后就可以增加列表。如果這樣做了,當終止程序時,新列表就會被保存。注意:實現(xiàn)一個小且實用的計算機化的電話號碼本只需要很少的程序代碼。/*Asimpletelephonenumberdatabasethatusesapropertylist.*/importjava.io.*;importjava.util.*;classPhonebook{publicstaticvoidmain(Stringargs[])throwsIOException{Propertiesht=newProperties();BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));Stringname,number;FileInputStreamfin=null; 52----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方booleanchanged=false;//Trytoopenphonebook.datfile.try{fin=newFileInputStream("phonebook.dat");}catch(FileNotFoundExceptione){//ignoremissingfile}/*Ifphonebookfilealreadyexists,loadexistingtelephonenumbers.*/try{if(fin!=null){ht.load(fin);fin.close();}}catch(IOExceptione){System.out.println("Errorreadingfile.");}//Letuserenternewnamesandnumbers.do{System.out.println("Enternewname"+"('quit'tostop):");name=br.readLine();if(name.equals("quit"))continue;System.out.println("Enternumber:");number=br.readLine();ht.put(name,number);changed=true;}while(!name.equals("quit"));//Ifphonebookdatahaschanged,saveit.if(changed){FileOutputStreamfout=newFileOutputStream("phonebook.dat");ht.store(fout,"TelephoneBook");fout.close();}//Lookupnumbersgivenaname.do{System.out.println("Enternametofind"+"('quit'toquit):");name=br.readLine();if(name.equals("quit"))continue;number=(String)ht.get(name);System.out.println(number);}while(!name.equals("quit")); 53----------專業(yè)最好文檔,專業(yè)為你服務,急你所急,供你所需-------------文檔下載最佳的地方}}15.11類集總結(jié)類集框架為程序員提供了一個功能強大的設計方案以解決編程過程中面臨的大多數(shù)任務。下一次當你需要存儲和檢索信息時,可考慮使用類集。記住,類集不僅僅是專為那些“大型作業(yè)”,例如聯(lián)合數(shù)據(jù)庫,郵件列表或產(chǎn)品清單系統(tǒng)等所專用的。它們對于一些小型作業(yè)也是很有效的。例如,TreeMap可以給出一個很好的類集以保留一組文件的字典結(jié)構(gòu)。TreeSet在存儲工程管理信息時是十分有用的。坦白地說,對于采用基于類集的解決方案而受益的問題種類只受限于你的想象力。
此文檔下載收益歸作者所有