




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
本章學(xué)習(xí)目標(biāo):●
理解泛型的概念●
掌握泛型類的創(chuàng)建和使用●
理解泛型的有界類型和通配符的使用,了解泛型的限制●
理解Java集合框架的結(jié)構(gòu)、迭代器接口●
掌握常用接口及實(shí)現(xiàn)類的使用●
了解集合轉(zhuǎn)換第十章泛型與集合第1節(jié)part泛型
從JDK5.0開始,Java引入“參數(shù)化類型(parameterizedtype)”的概念,這種參數(shù)化類型稱為“泛型(Generic)”。泛型是將數(shù)據(jù)類型參數(shù)化,即在編寫代碼時(shí)將數(shù)據(jù)類型定義成參數(shù),這些類型參數(shù)在使用之前再進(jìn)行指明。泛型提高了代碼的重用性,使得程序更加靈活、安全和簡(jiǎn)潔。泛型本節(jié)概述
在JDK5.0之前,為了實(shí)現(xiàn)參數(shù)類型的任意化,都是通過Object類型來處理。但這種處理方式所帶來的缺點(diǎn)是需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,此種強(qiáng)制類型轉(zhuǎn)換不僅使代碼臃腫,而且要求程序員必須對(duì)實(shí)際所使用的參數(shù)類型已知的情況下才能進(jìn)行,否則容易引起ClassCastException異常。
從JDK5.0開始,Java增加對(duì)泛型的支持。使用泛型之后就不會(huì)出現(xiàn)上述問題。泛型的好處是在程序編譯期會(huì)對(duì)類型進(jìn)行檢查,捕捉類型不匹配錯(cuò)誤,以免引起ClassCastException異常;而且泛型不需要進(jìn)行強(qiáng)制轉(zhuǎn)換,數(shù)據(jù)類型都是自動(dòng)轉(zhuǎn)換的。
泛型經(jīng)常使用在類、接口和方法的定義中,分別稱為泛型類、泛型接口和泛型方法。泛型類是引用類型,在內(nèi)存堆中。10.1.1泛型定義泛型定義定義泛型類的語法格式如下:[訪問符]class類名<類型參數(shù)列表>{ //類體......}其中:(1)尖括號(hào)中是類型參數(shù)列表,可以由多個(gè)類型參數(shù)組成,多個(gè)類型參數(shù)之間使用“,”隔開。(2)類型參數(shù)只是占位符,一般使用大寫的“T”、“U”、“V”等作為類型參數(shù)。下述代碼示例了泛型類的定義,代碼如下所示。classNode<T>{ privateTdata; publicNode<T>next; //省略......}10.1.1泛型定義泛型定義
從Java7開始,實(shí)例化泛型類時(shí)只需給出一對(duì)尖括號(hào)“<>”即可,Java可以推斷尖括號(hào)中的泛型信息。將兩個(gè)尖括號(hào)放在一起像一個(gè)菱形,因此也被稱為“菱形”語法。Java7“菱形”語法實(shí)例化泛型類的格式如下:
類名<類型參數(shù)列表>對(duì)象=new類名<>([構(gòu)造方法參數(shù)列表]);
例如:Node<String>myNode=newNode<>();
下述代碼示例了一個(gè)泛型類的定義,代碼如下所示。10.1.1泛型定義【代碼10.1】Generic.javapackagecom;publicclassGeneric<T>{ privateTdata; publicGeneric(){ }publicGeneric(Tdata){ this.data=data;}publicTgetData(){ returndata; } publicvoidsetData(Tdata){ this.data=data; } publicvoidshowDataType(){System.out.println("數(shù)據(jù)的類型是:"+data.getClass().getName());}}10.1.1泛型定義
上述代碼定義了一個(gè)名為Generic的泛型類,并提供兩個(gè)構(gòu)造方法。私有屬性data的數(shù)據(jù)類型采用泛型,可以在使用時(shí)在進(jìn)行指定。showDataType()方法顯示data屬性的具體類型名稱,其中“getClass().getName()”用于獲取對(duì)象的類名。
下述代碼示例了泛型類的實(shí)例化,并訪問相應(yīng)方法,代碼如下所示?!敬a10.2】GenericExample.javapackagecom;publicclassGenericExample{ publicstaticvoidmain(String[]args){ Generic<String>str=newGeneric<>("字符串類型泛型類!"); str.showDataType(); System.out.println(str.getData()); System.out.println("----------------------------------"); //定義泛型類的一個(gè)Double版本 Generic<Double>dou=newGeneric<>(3.1415); dou.showDataType(); System.out.println(dou.getData()); }}10.1.1泛型定義
上述代碼使用Generic泛型類,并分別實(shí)例化為String和Double兩種不同類型的對(duì)象。程序運(yùn)行結(jié)果如下:
數(shù)據(jù)的類型是:java.lang.String
歡迎使用泛型類!----------------------------------
數(shù)據(jù)的類型是:java.lang.Double3.141510.1.2通配符通配符當(dāng)使用一個(gè)泛型類時(shí)(包括聲明泛型變量和創(chuàng)建泛型實(shí)例對(duì)象),都應(yīng)該為此泛型類傳入一個(gè)實(shí)參,否則編譯器會(huì)提出泛型警告。假設(shè)現(xiàn)在定義一個(gè)方法,該方法的參數(shù)需要使用泛型,但類型參數(shù)是不確定的,此時(shí)如果考慮使用Object類型來解決,編譯時(shí)則會(huì)出現(xiàn)錯(cuò)誤。以之前定義的泛型類Generic為例,考慮如下代碼:【代碼10.3】NoWildcardExample.javapackagecom;publicclassNoWildcardExample{ publicstaticvoidmyMethod(Generic<Object>g){ g.showDataType(); } publicstaticvoidmain(String[]args){ //參數(shù)類型是Object Generic<Object>gstr=newGeneric<Object>("Object"); myMethod(gstr); //參數(shù)類型是Integer Generic<Integer>gint=newGeneric<Integer>(12); //這里將產(chǎn)生一個(gè)錯(cuò)誤 myMethod(gint); //參數(shù)類型是Integer Generic<Double>gdou=newGeneric<Double>(12.0); //這里將產(chǎn)生一個(gè)錯(cuò)誤 myMethod(gdou); }}10.1.2通配符
上述代碼中定義的myMethod()方法的參數(shù)是泛型類Generic,該方法的意圖是能夠處理各種類型參數(shù),但在使用Generic類時(shí)必須指定具體的類型參數(shù),此處在不使用通配符的情況下,只能使用“Generic<Object>”的方式。這種方式將造成main()方法中的語句編譯時(shí)產(chǎn)生類型不匹配的錯(cuò)誤,程序無法運(yùn)行。程序中出現(xiàn)的這個(gè)問題,可以使用通配符解決。通配符是由“?”來表示一個(gè)未知類型,從而解決類型被限制、不能動(dòng)態(tài)根據(jù)實(shí)例進(jìn)行確定的缺點(diǎn)。下述代碼使用通配符“?”重新實(shí)現(xiàn)上述處理過程,實(shí)現(xiàn)處理各種類型參數(shù)的情況,代碼如下所示。10.1.2通配符【代碼10.4】UseWildcardExample.javapackagecom;publicclassUseWildcardExample{ publicstaticvoidmyMethod(Generic<?>g){ g.showDataType(); } publicstaticvoidmain(String[]args){ //參數(shù)類型是String Generic<String>gstr=newGeneric<>("Object"); myMethod(gstr); //參數(shù)類型是Integer Generic<Integer>gint=newGeneric<>(12); myMethod(gint); //參數(shù)類型是Integer Generic<Double>gdou=newGeneric<>(12.0); myMethod(gdou); }}10.1.2通配符
上述代碼定義了myMethod()方法時(shí),使用“Generic<?>”通配符的方式作為類型參數(shù),如此便能夠處理各種類型參數(shù),且程序編譯無誤,能夠正常運(yùn)行。程序運(yùn)行結(jié)果如下:
數(shù)據(jù)的類型是:java.lang.String
數(shù)據(jù)的類型是:java.lang.Integer
數(shù)據(jù)的類型是:java.lang.Double有界類型
泛型的類型參數(shù)可以是各種類型,但有時(shí)候需要對(duì)類型參數(shù)的取值進(jìn)行一定程度的限制,以便類型參數(shù)在指定范圍內(nèi)。針對(duì)這種情況,Java提供了“有界類型”,來限制類型參數(shù)的取值范圍。有界類型分兩種:
(1)使用extends關(guān)鍵字聲明類型參數(shù)的上界。
(2)使用super關(guān)鍵字聲明類型參數(shù)的下界。10.1.3有界類型有界類型1.上界
使用extends關(guān)鍵字可以指定類型參數(shù)的上界,限制此類型參數(shù)必須繼承自指定的父類或父類本身。被指定的父類則稱為類型參數(shù)的“上界(upperbound)”。
類型參數(shù)的上界可以在定義泛型時(shí)進(jìn)行指定,也可以在使用泛型時(shí)進(jìn)行指定,其語法格式分別如下://定義泛型時(shí)指定類型參數(shù)的上界[訪問符]class類名<類型參數(shù)extends父類>{ //類體......}//使用泛型時(shí)指定類型參數(shù)的上界
泛型類<?extends父類>
例如://定義泛型時(shí)指定類型參數(shù)的上界publicclassGeneric<TextendsNumber>{ //類體......}//使用泛型時(shí)指定類型參數(shù)的上界Generic<?extendsNumber>
上述代碼限制了泛型類Generic的類型參數(shù)必須是Number類及其子類,因此可以將Number類稱為此類型參數(shù)的上界。Java中Number類是一個(gè)抽象類,所有數(shù)值類都繼承此抽象類,即Integer、Long、Float、Double等用于數(shù)值操作的類都繼承Number類。10.1.3有界類型下述代碼示例了使用類型參數(shù)的上界,代碼如下所示?!敬a10.5】UpBoundGenericExample.javapackagecom;classUpBoundGeneric<TextendsNumber>{ privateTdata; publicUpBoundGeneric(){ } publicUpBoundGeneric(Tdata){ this.data=data; } publicTgetData(){ returndata; } publicvoidsetData(Tdata){ this.data=data; } publicvoidshowDataType(){ System.out.println("數(shù)據(jù)的類型是:"+data.getClass().getName()); }}10.1.3有界類型publicclassUpBoundGenericExample{ //使用泛型Generic時(shí)指定其類型參數(shù)的上界 publicstaticvoidmyMethod(Generic<?extendsNumber>g){ g.showDataType(); } publicstaticvoidmain(String[]args){ //參數(shù)類型是Integer Generic<Integer>gint=newGeneric<>(1); myMethod(gint); //參數(shù)類型是Long Generic<Long>glong=newGeneric<>(10L); myMethod(glong); //參數(shù)類型是String Generic<String>gstr=newGeneric<>("String"); //產(chǎn)生錯(cuò)誤 //myMethod(gstr);10.1.3有界類型 //使用已經(jīng)限定參數(shù)的泛型UpBoundGeneric UpBoundGeneric<Integer>ubgint=newUpBoundGeneric<>(20); ubgint.showDataType(); UpBoundGeneric<Long>ubglon=newUpBoundGeneric<>(20L); ubglon.showDataType(); //產(chǎn)生錯(cuò)誤 //UpBoundGeneric<String>ubgstr=newUpBoundGeneric<>("指定上界"); }}10.1.3有界類型
上述代碼中定義了一個(gè)泛型類UpBoundGeneric,并指定其類型參數(shù)的上界是Number類。在定義myMethod()方法時(shí)指定泛型類Generic的類型參數(shù)的上界也是Number類。在main()方法中進(jìn)行使用時(shí),當(dāng)類型參數(shù)不是Number的子類時(shí)都會(huì)產(chǎn)生錯(cuò)誤。因UpBoundGeneric類在定義時(shí)就已經(jīng)限定了類型參數(shù)的上界,所以出現(xiàn)“UpBoundGeneric<String>”就會(huì)報(bào)錯(cuò)。Generic類在定義時(shí)并沒有上界限定,而是在定義myMethod()方法使用Generic類才進(jìn)行限定的,因此出現(xiàn)“Generic<String>”不會(huì)報(bào)錯(cuò),調(diào)用“myMethod(gstr)”時(shí)才會(huì)報(bào)錯(cuò)。
程序運(yùn)行結(jié)果如下所示:
數(shù)據(jù)的類型是:java.lang.Integer
數(shù)據(jù)的類型是:java.lang.Long
數(shù)據(jù)的類型是:java.lang.Integer
數(shù)據(jù)的類型是:java.lang.Long2.下界
使用super關(guān)鍵字可以指定類型參數(shù)的下界,限制此類型參數(shù)必須是指定的類型本身或其父類,直至Object類。被指定的類則稱為類型參數(shù)的“下界(lowerbound)”。
類型參數(shù)的下界通常在使用泛型時(shí)進(jìn)行指定,其語法格式如下所示:
泛型類<?super類型>
例如:Generic<?superString>
上述代碼限制了泛型類Generic的類型參數(shù)必須是String類本身或其父類Object,因此可以將String類稱為此類型參數(shù)的下界。
下述代碼示例泛型類型參數(shù)下界的聲明和使用,代碼如下所示。10.1.3有界類型【代碼10.6】LowBoundGenericExample.javapackagecom;publicclassLowBoundGenericExample{ //使用泛型Generic時(shí)指定其類型參數(shù)的下界 publicstaticvoidmyMethod(Generic<?superString>g){ g.showDataType(); }
publicstaticvoidmain(String[]args){ //參數(shù)類型是String Generic<String>gstr=newGeneric<>("String類本身"); myMethod(gstr); //參數(shù)類型是Object Generic<Object>gobj=newGeneric<Object>(10); myMethod(gobj); //參數(shù)類型是Integer Generic<Integer>gint=newGeneric<>(10); //產(chǎn)生錯(cuò)誤 //myMethod(gint); }}10.1.3有界類型
上述代碼在定義myMethod()方法時(shí)指定泛型類Generic的類型參數(shù)的上界是String類,因此在main()方法中進(jìn)行使用時(shí),當(dāng)參數(shù)類型不是String類或其父類Object時(shí),都會(huì)產(chǎn)生錯(cuò)誤。程序運(yùn)行結(jié)果如下:
數(shù)據(jù)的類型是:java.lang.String
數(shù)據(jù)的類型是:java.lang.Integer
泛型中使用extends關(guān)鍵字限制類型參數(shù)必須是指定的類本身或其子類,而super關(guān)鍵字限制類型參數(shù)必須是指定的類本身或其父類。在泛型中經(jīng)常使用extends關(guān)鍵字指定上界,而很少使用super關(guān)鍵字指定下界。10.1.3有界類型Java語言沒有真正實(shí)現(xiàn)泛型。Java程序在編譯時(shí)生成的字節(jié)碼中是不包含泛型信息的,泛型的類型信息將在編譯處理時(shí)被擦除掉,這個(gè)過程稱為類型擦除。這種實(shí)現(xiàn)理念造成Java泛型本身有很多漏洞,雖然Java8對(duì)類型推斷進(jìn)行了改進(jìn),但依然需要對(duì)泛型的使用上做一些限制,其中大多數(shù)限制都是由類型擦除和轉(zhuǎn)換引起的。Java對(duì)泛型的限制如下:
(1)泛型的類型參數(shù)只能是類類型(包括自定義類),不能是簡(jiǎn)單類型。
(2)同一個(gè)泛型類可以有多個(gè)版本(不同參數(shù)類型),不同版本的泛型類的實(shí)例是不兼容的,例如:“Generic<String>”與“Generic<Integer>”的實(shí)例是不兼容的。
(3)定義泛型時(shí),類型參數(shù)只是占位符,不能直接實(shí)例化,例如:“newT()”是錯(cuò)誤的。
(4)不能實(shí)例化泛型數(shù)組,除非是無上界的類型通配符,例如:“Generic<String>[]a=newGeneric<String>[10]”是錯(cuò)誤的,而“Generic<?>[]a=newGeneric<?>[10]”是被允許的。
(5)泛型類不能繼承Throwable及其子類,即泛型類不能是異常類,不能拋出也不能捕獲泛型類的異常對(duì)象,
例如:“classGenericException<T>extendsException”、“catch(Te)”都是錯(cuò)誤的。10.1.4泛型的限制泛型的限制第2節(jié)part集合概述Java的集合類是一些常用的數(shù)據(jù)結(jié)構(gòu),例如:隊(duì)列、棧、鏈表等。Java集合就像一種“容器”,用于存儲(chǔ)數(shù)量不等的對(duì)象,并按照規(guī)范實(shí)現(xiàn)一些常用的操作和算法。程序員在使用Java的集合類時(shí),不必考慮數(shù)據(jù)結(jié)構(gòu)和算法的具體實(shí)現(xiàn)細(xì)節(jié),根據(jù)需要直接使用這些集合類并調(diào)用相應(yīng)的方法即可,從而提高了開發(fā)效率。集合概述本節(jié)概述10.2.1集合框架
在JDK5.0之前,Java集合會(huì)丟失容器中所有對(duì)象的數(shù)據(jù)類型,將所有對(duì)象都當(dāng)成Object類型進(jìn)行處理。從JDK5.0增加泛型之后,Java集合完全支持泛型,可以記住容器中對(duì)象的數(shù)據(jù)類型,從而可以編寫更簡(jiǎn)潔、健壯的代碼。Java所有的集合類都在java.util包下,從JDK5.0開始為了處理多線程環(huán)境下的并發(fā)安全問題,又在java.util.concurrent包下提供了一些多線程支持的集合類。Java的集合類主要由兩個(gè)接口派生而出:Collection和Map,這兩個(gè)接口派生出一些子接口或?qū)崿F(xiàn)類。Collection和Map是集合框架的根接口,如圖10.1所示是Collection集合體系的繼承樹。集合框架10.2.1集合框架Collection接口下有3個(gè)子接口:(1)Set接口:無序、不可重復(fù)的集合;(2)Queue接口:隊(duì)列集合;(3)List接口:有序、可以重復(fù)的集合。10.2.1集合框架
如圖10.2所示是Map集合體系的繼承樹。
所有Map的實(shí)現(xiàn)類用于保存具有映射關(guān)系的數(shù)據(jù),即Map保存的每項(xiàng)數(shù)據(jù)都是由key-value鍵值對(duì)組成。Map中的key用于標(biāo)識(shí)集合中的每項(xiàng)數(shù)據(jù),是不可重復(fù)的,可以通過key來獲取Map集合中的數(shù)據(jù)項(xiàng)。10.2.1集合框架Java中的集合分為三大類:
(1)Set集合:將一個(gè)對(duì)象添加到Set集合時(shí),Set集合無法記住添加的順序,因此Set集合中的元素不能重復(fù),否則系統(tǒng)無法識(shí)別該元素,訪問Set集合中的元素也只能根據(jù)元素本身進(jìn)行訪問;
(2)List集合:與數(shù)組類似,List集合可以記住每次添加元素的順序,因此可以根據(jù)元素的索引訪問List集合中的元素,List集合中的元素可以重復(fù)且長度是可變的;
(3)Map集合:每個(gè)元素都是有key/value鍵值對(duì)組成,可以根據(jù)每個(gè)元素的key來訪問對(duì)應(yīng)的value,Map集合中的key不允許重復(fù),value可以重復(fù)。
本章主要介紹常用的集合接口及其實(shí)現(xiàn)類,例如List、Set、Map和Queue集合接口,以及對(duì)應(yīng)的實(shí)現(xiàn)類ArrayList、HashSet、HashMap和LinkedList。10.2.2迭代器接口
迭代器(Iterator)可以采用統(tǒng)一的方式對(duì)Collection集合中的元素進(jìn)行遍歷操作,開發(fā)人員無需關(guān)心Collection集合中的內(nèi)容,也不必實(shí)現(xiàn)IEnumerable或者IEnumerator接口就能夠使用foreach循環(huán)遍歷集合中的部分或全部元素。Java從JDK5.0開始增加了Iterable新接口,該接口是Collection接口的父接口,因此所有實(shí)現(xiàn)了Iterable的集合類都是可迭代的,都支持foreach循環(huán)遍歷。Iterable接口中的iterator()方法可以獲取每個(gè)集合自身的迭代器Iterator。Iterator是集合的迭代器接口,定義了常見的迭代方法,用于訪問、操作集合中的元素。Iterator接口中的方法如表10-1所示:迭代器接口10.2.2迭代器接口下述代碼示范了Iterator接口中的方法的應(yīng)用,代碼如下所示。【代碼10.7】IteratorExample.javapackagecom;importjava.util.Collection;importjava.util.HashSet;importjava.util.Iterator;publicclassIteratorExample{ publicstaticvoidmain(String[]args){ //創(chuàng)建一個(gè)集合 Collectioncity=newHashSet<>(); city.add("重慶"); city.add("成都"); city.add("北京"); city.add("上海"); //直接顯示集合元素: System.out.print("開始的城市有:"+city+""); System.out.println();10.2.2迭代器接口 //獲取city集合對(duì)應(yīng)的迭代器 Iteratorit=city.iterator(); while(it.hasNext()){ //it.next()方法返回的數(shù)據(jù)類型是Object類型,需要強(qiáng)制轉(zhuǎn)換 Stringc=(String)it.next(); System.out.print(c+""); if(c.equals("成都")) it.remove(); } System.out.println(); System.out.print("最后的城市有:"+city+""); }}程序運(yùn)行結(jié)果如下:開始的城市有:[上海,北京,重慶,成都]上海
北京
重慶
成都
最后的城市有:[上海,北京,重慶]第3節(jié)part集合類10.3.1Collection接口Collection接口是Set、Queue和List接口的父接口,該接口中定義的方法可以操作這三個(gè)接口中的任一個(gè)集合,Collection接口中常用的方法如表10-2所示。Collection接口10.3.1
使用Collection需要注意以下幾點(diǎn)問題:
(1)add()、addAll()、remove()、removeAll()和retainAll()方法可能會(huì)引發(fā)不支持該操作的UnsupportedOperationException異常。
(2)將一個(gè)不兼容的對(duì)象添加到集合中時(shí),將產(chǎn)生ClassCastException異常。
(3)Collection接口沒有提供獲取得某個(gè)元素的方法,但可以通過iterator()方法獲取迭代器來遍歷集合中的所有元素.
(4)雖然Collection中可以存儲(chǔ)任何Object對(duì)象,但不建議在同一個(gè)集合容器中存儲(chǔ)不同類型的對(duì)象,建議使用泛型增強(qiáng)集合的安全性,以免引起ClassCastException異常。
下述代碼示例了如何操作Collection集合里的元素,代碼如下所示。Collection接口10.3.1【代碼10.8】CollectionExample.javapackagecom;importjava.util.ArrayList;importjava.util.Collection;publicclassCollectionExample{ publicstaticvoidmain(String[]args){ //創(chuàng)建一個(gè)Collection對(duì)象的集合,該集合用ArrayList類實(shí)例化 Collection<Comparable>c=newArrayList<>(); //添加元素 c.add("Java程序設(shè)計(jì)"); c.add(12); c.add("Android程序設(shè)計(jì)"); System.out.println("c集合元素的個(gè)數(shù)為:"+c.size()); //刪除指定元素 c.remove(12); System.out.println("刪除后,c集合元素的個(gè)數(shù)為:"+c.size()); //判斷集合是否包含指定元素 System.out.println(“集合中是否包含\”Java程序設(shè)計(jì)\“字符串:”+c.contains(“Java程序設(shè)計(jì)”));Collection接口10.3.1 //查看c集合的所有元素 System.out.println("c集合的元素有:"+c); //清空集合中的元素 c.clear(); //判斷集合是否為空 System.out.println("c集合是否為空:"+c.isEmpty()); }}程序運(yùn)行結(jié)果如下:c集合元素的個(gè)數(shù)為:3刪除后,c集合元素的個(gè)數(shù)為:2集合中是否包含"Java程序設(shè)計(jì)"字符串:truec集合的元素有:[Java程序設(shè)計(jì),Android程序設(shè)計(jì)]c集合是否為空:trueCollection接口10.3.2List接口及其實(shí)現(xiàn)類List是Collection接口的子接口,可以使用Collection接口中的全部方法。因?yàn)長ist是有序、可重復(fù)的集合,所以List接口中又增加一些根據(jù)索引操作集合元素的方法,常用的方法如表10-3所示。List接口及其實(shí)現(xiàn)類10.3.2List接口及其實(shí)現(xiàn)類List集合默認(rèn)按照元素添加順序設(shè)置元素的索引,索引從0開始,例如:第一次添加的元素索引為0,第二次添加的元素索引為1,第n次添加的元素索引為n-1。當(dāng)使用無效的索引時(shí)將產(chǎn)生IndexOutOfBoundsException異常。ArrayList和Vector是List接口的兩個(gè)典型實(shí)現(xiàn)類,完全支持List接口的所有功能方法。ArrayList稱為“數(shù)組列表”,而Vector稱為“向量”,兩者都是基于數(shù)組實(shí)現(xiàn)的列表集合,但該數(shù)組是一個(gè)動(dòng)態(tài)的、長度可變的、并允許再分配的Object[]數(shù)組。ArrayList和Vector在用法上幾乎完全相同,但由于Vector從JDK1.0開始就有了,所以Vector中提供了一些方法名很長的方法,例如:addElement()方法,該方法跟add()方法沒有任何區(qū)別。10.3.2List接口及其實(shí)現(xiàn)類ArrayList和Vector雖然在用法上相似,但兩者在本質(zhì)上還是存在區(qū)別的:
(1)ArrayList是非線程安全的,當(dāng)多個(gè)線程訪問同一個(gè)ArrayList集合時(shí),如果多個(gè)線程同時(shí)修改ArrayList集合中的元素,則程序必須手動(dòng)保證該集合的同步性。
(2)Vector是線程安全的,程序無需手動(dòng)保證該集合的同步性。正因?yàn)閂ector是線程安全的,所以Vector的性能要比ArrayList低。在實(shí)際應(yīng)用中,即使要保證線程安全,也不推薦使用Vector,因?yàn)榭梢允褂肅ollections工具類將一個(gè)ArrayList變成線程安全的。
下述代碼示例了ArrayList類的使用,代碼如下所示。10.3.2List接口及其實(shí)現(xiàn)類【代碼10.9】ArrayListExample.javapackagecom;importjava.util.ArrayList;importjava.util.Iterator;publicclassArrayListExample{publicstaticvoidmain(String[]args){ //使用泛型ArrayList集合 ArrayList<String>array=newArrayList<>(); //添加元素 array.add("北京"); array.add("上海"); array.add("廣州"); array.add("重慶"); array.add("深圳"); System.out.print("使用foreach遍歷集合:"); for(Strings:array){ System.out.print(s+""); } System.out.println(); System.out.print("使用Iterator迭代器遍歷集合:");10.3.2List接口及其實(shí)現(xiàn)類 //獲取迭代器對(duì)象 Iterator<String>it=array.iterator(); while(it.hasNext()){ System.out.print(it.next()+""); } //刪除指定索引和指定名稱的元素 array.remove(0); array.remove("廣州"); System.out.println(); System.out.print("刪除后的元素有:"); for(Strings:array){ System.out.print(s+""); } }}程序運(yùn)行結(jié)果如下:使用foreach遍歷集合:北京
上海
廣州
重慶
深圳
使用Iterator迭代器遍歷集合:北京
上海
廣州
重慶
深圳
刪除后的元素有:上海
重慶
深圳10.3.3Set接口及其實(shí)現(xiàn)類Set集合類似一個(gè)罐子,可以將多個(gè)元素丟進(jìn)罐子里,但不能記住元素的添加順序,因此不允許包含相同的元素。Set接口繼承Collection接口,沒有提供任何額外的方法,其用法與Collection一樣,只是特性不同(Set中的元素不重復(fù))。Set接口常用的實(shí)現(xiàn)類包括HashSet、TreeSet和EnumSet,這三個(gè)實(shí)現(xiàn)類各具特色:
(1)HashSet是Set接口的典型實(shí)現(xiàn)類,大多數(shù)使用Set集合時(shí)都使用該實(shí)現(xiàn)類。HashSet使用Hash算法來存儲(chǔ)集合中的元素,具有良好的存、取以及查找性。
(2)TreeSet采用Tree“樹”的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)集合元素,因此可以保證集合中的元素處于排序狀態(tài)。TreeSet支持兩種排序方式:自然排序和定制排序,默認(rèn)情況下采用自然排序。
(3)EnumSet是一個(gè)專為枚舉類設(shè)計(jì)的集合類,其所有元素必須是指定的枚舉類型。EnumSet集合中的元素也是有序的,按照枚舉值順序進(jìn)行排序Set接口及其實(shí)現(xiàn)類10.3.3Set接口及其實(shí)現(xiàn)類HashSet及其子類都是采用Hash算法來決定集合中元素的存儲(chǔ)位置,并通過Hash算法來控制集合的大小。Hash表中可以存儲(chǔ)元素的位置稱為“桶(bucket)”,通常情況下,單個(gè)桶只存儲(chǔ)一個(gè)元素,此時(shí)性能最佳,Hash算法可以根據(jù)HashCode值計(jì)算出桶的位置,并從桶中取出元素。但當(dāng)發(fā)生Hash沖突時(shí),單個(gè)桶會(huì)存儲(chǔ)多個(gè)元素,這些元素以鏈表的形式存儲(chǔ)。
下述代碼示例了HashSet實(shí)現(xiàn)類的具體應(yīng)用,代碼如下所示。10.3.3Set接口及其實(shí)現(xiàn)類【代碼10.10】HashSetExample.javapackagecom;importjava.util.HashSet;importjava.util.Iterator;publicclassHashSetExample{publicstaticvoidmain(String[]args){ //使用泛型HashSet HashSet<Integer>hs=newHashSet<>(); //向集合中添加元素 hs.add(12); hs.add(3); hs.add(24); hs.add(24); hs.add(5); //直接輸出HashSet集合對(duì)象 System.out.println(hs); //使用foreach循環(huán)遍歷 for(inta:hs){ System.out.print(a+""); } System.out.println(); hs.remove(3);//刪除指定元素 System.out.print("刪除后剩下的數(shù)據(jù):"); //獲取HashSet的迭代器 Iterator<Integer>iterator=hs.iterator(); //使用迭代器遍歷 while(iterator.hasNext()){ System.out.print(iterator.next()+""); }}}程序運(yùn)行結(jié)果如下:[3,5,24,12]352412刪除后剩下的數(shù)據(jù):52412通過運(yùn)行結(jié)果可以發(fā)現(xiàn),HashSet集合中的元素是無序的,且沒有重復(fù)元素。10.3.3Set接口及其實(shí)現(xiàn)類下述代碼示例了TreeSet實(shí)現(xiàn)類的使用,代碼如下所示?!敬a10.11】TreeSetExample.javapackagecom;importjava.util.Iterator;importjava.util.TreeSet;publicclassTreeSetExample{publicstaticvoidmain(String[]args){ TreeSet<String>hs=newTreeSet<>(); hs.add("上海"); hs.add("重慶"); hs.add("廣州"); hs.add("成都"); hs.add("重慶"); System.out.println(hs); for(Stringstr:hs){ System.out.print(str+""); } hs.remove("重慶"); System.out.println(); System.out.print("刪除后剩下的數(shù)據(jù):"); Iterator<String>iterator=hs.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+""); }}}
程序運(yùn)行結(jié)果如下:[上海,廣州,成都,重慶]
上海
廣州
成都
重慶
刪除后剩下的數(shù)據(jù):上海
廣州
成都
通過運(yùn)行結(jié)果可以看出,TreeSet集合中的元素安照字符串的內(nèi)容進(jìn)行排序,輸出的元素都是有序的,但也不能包含重復(fù)元素。10.3.4Queue接口及其實(shí)現(xiàn)類Queue用于模擬隊(duì)列這種數(shù)據(jù)結(jié)構(gòu),通常以“先進(jìn)先出(FIFO)”的方式排序各個(gè)元素,即最先入隊(duì)的元素最先出隊(duì)。Queue接口繼承Collection接口,除了Collection接口中的基本操作外,還提供了隊(duì)列的插入、提取和檢查操作,且每個(gè)操作都存在兩種形式:一種操作失敗時(shí)拋出異常;另一種操作失敗時(shí)返回一個(gè)特殊值(null或false)。Queue接口中的常用方法如表10-4所示。Queue接口及其實(shí)現(xiàn)類10.3.4Queue接口及其實(shí)現(xiàn)類Queue接口有一個(gè)PriorityQueue實(shí)現(xiàn)類。PriorityQueue類是基于優(yōu)先級(jí)的無界隊(duì)列,通常稱為“優(yōu)先級(jí)隊(duì)列”。優(yōu)先級(jí)隊(duì)列的元素按照其自然順序或定制排序,優(yōu)先級(jí)隊(duì)列不允許使用null元素,依靠自然順序的優(yōu)先級(jí)隊(duì)列不允許插入不可比較的對(duì)象。下述代碼示例了PriorityQueue實(shí)現(xiàn)類的使用,代碼如下所示。Queue接口及其實(shí)現(xiàn)類10.3.4Queue接口及其實(shí)現(xiàn)類【代碼10.12】PriorityQueueExample.javapackagecom;importjava.util.Iterator;importjava.util.PriorityQueue;publicclassPriorityQueueExample{publicstaticvoidmain(String[]args){ PriorityQueue<Integer>pq=newPriorityQueue<>(); pq.offer(6); pq.offer(-3); pq.offer(20); pq.offer(18); System.out.println(pq); //訪問隊(duì)列的第一個(gè)元素 System.out.println(“poll:”+pq.poll()); System.out.print(“foreach遍歷:”); for(Integere:pq){ System.out.print(e+“”); } System.out.println(); System.out.print(“迭代器遍歷:”); Iterator<Integer>iterator=pq.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+“”); }}}程序運(yùn)行結(jié)果如下:[-3,6,20,18]poll:-3foreach遍歷:61820迭代器遍歷:6182010.3.4Queue接口及其實(shí)現(xiàn)類
除此之外,Queue還有一個(gè)Deque接口,Deque代表一個(gè)“雙端隊(duì)列”,雙端隊(duì)列可以同時(shí)從兩端來添加、刪除元素。Deque接口中定義在雙端隊(duì)列兩端插入、移除和檢查元素的方法,其常用方法如表10-5所示。10.3.4Queue接口及其實(shí)現(xiàn)類Java為Deque提供了ArrayDeque和LinkedList兩個(gè)實(shí)現(xiàn)類。ArrayDeque稱為“數(shù)組雙端隊(duì)列”,是Deque接口的實(shí)現(xiàn)類,其特點(diǎn)如下:
(1)ArrayDeque沒有容量限制,可以根據(jù)需要增加容量;
(2)ArrayDeque不是基于線程安全的,在沒有外部代碼同步時(shí),不支持多個(gè)線程的并發(fā)訪問;
(3)ArrayDeque禁止添加null元素;
(4)ArrayDeque在用作堆棧時(shí)快于Stack,在用作隊(duì)列時(shí)快于LinkedList。
下述代碼示例了ArrayDeque實(shí)現(xiàn)類的使用,代碼如下所示。10.3.4Queue接口及其實(shí)現(xiàn)類【代碼10.13】ArrayDequeExample.javapackagecom;importjava.util.*;publicclassArrayDequeExample{publicstaticvoidmain(String[]args){ //使用泛型ArrayDeque集合 ArrayDeque<String>queue=newArrayDeque<>(); //在隊(duì)尾添加元素 queue.offer("上海"); //在隊(duì)頭添加元素 queue.push("北京"); //在隊(duì)頭添加元素 queue.offerFirst("南京"); //在隊(duì)尾添加元素 queue.offerLast("重慶"); System.out.print("直接輸出ArrayDeque集合對(duì)象:"+queue); System.out.println(); System.out.println("peek訪問隊(duì)列頭部的元素:"+queue.peek()); System.out.println("peek訪問后的隊(duì)列元素:"+queue); //System.out.println("------------------");10.3.4Queue接口及其實(shí)現(xiàn)類 //poll出第一個(gè)元素 System.out.println("poll出第一個(gè)元素為:"+queue.poll()); System.out.println("poll訪問后的隊(duì)列元素::"+queue); System.out.println("foreach遍歷:"); //使用foreach循環(huán)遍歷 for(Stringstr:queue){ System.out.print(str+""); } System.out.println(); System.out.println("迭代器遍歷:"); //獲取ArrayDeque的迭代器 Iterator<String>iterator=queue.iterator(); //使用迭代器遍歷 while(iterator.hasNext()){ System.out.print(iterator.next()+""); }}}10.3.4Queue接口及其實(shí)現(xiàn)類程序運(yùn)行結(jié)果如下:直接輸出ArrayDeque集合對(duì)象:[南京,北京,上海,重慶]peek訪問隊(duì)列頭部的元素:南京peek訪問后的隊(duì)列元素:[南京,北京,上海,重慶]poll出第一個(gè)元素為:南京poll訪問后的隊(duì)列元素::[北京,上海,重慶]foreach遍歷:北京
上海
重慶
迭代器遍歷:北京
上海
重慶
10.3.4Map接口及其實(shí)現(xiàn)類Map接口是集合框架的另一個(gè)根接口,與Collection接口并列。Map是以key/value
鍵值對(duì)映射關(guān)系存儲(chǔ)的集合。Map接口中的常用方法如表10-6所示。Map接口及其實(shí)現(xiàn)類10.3.4Map接口及其實(shí)現(xiàn)類HashMap和TreeMap是Map體系中兩個(gè)常用實(shí)現(xiàn)類,其特點(diǎn)如下:
(1)HashMap是基于哈希算法的Map接口的實(shí)現(xiàn)類,該實(shí)現(xiàn)類提供所有映射操作,并允許使用null鍵和null值,但不能保證映射的順序,即是無序的映射集合。
(2)TreeMap是基于“樹”結(jié)構(gòu)來存儲(chǔ)的Map接口實(shí)現(xiàn)類,可以根據(jù)其鍵的自然順序進(jìn)行排序,或定制排序方式。
下述代碼演示了HashMap類的使用,代碼如下所示。10.3.4Map接口及其實(shí)現(xiàn)類【代碼10.14】HashMapExample.javapackagecom;importjava.util.HashMap;publicclassHashMapExample{publicstaticvoidmain(String[]args){ //使用泛型HashMap集合 HashMap<Integer,String>hm=newHashMap<>(); //添加數(shù)據(jù),key-value鍵值對(duì)形式 hm.put(1,“北京”); hm.put(2,“上?!?; hm.put(3,“武漢”); hm.put(4,“重慶”); hm.put(5,“成都”); hm.put(null,null); //根據(jù)key獲取value System.out.println(hm.get(1)); System.out.println(hm.get(3)); System.out.println(hm.get(5)); System.out.println(hm.get(null)); //根據(jù)key刪除 hm.remove(1); //key為1的元素已經(jīng)刪除,返回null System.out.println(hm.get(1));}}
上述代碼允許向HashMap中添加null鍵和null值,當(dāng)使用get()方法獲取元素時(shí),沒用指定的鍵時(shí)會(huì)返回null。程序運(yùn)行結(jié)果如下:
北京
武漢
成都nullnull10.3.4Map接口及其實(shí)現(xiàn)類下述代碼演示了TreeMap類的使用,代碼如下所示?!敬a10.15】TreeMapExample.javapackagecom;importjava.util.TreeMap;publicclassTreeMapExample{publicstaticvoidmain(String[]args){ //使用泛型TreeMap集合 TreeMap<Integer,String>tm=newTreeMap<
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 廣東公務(wù)員行測(cè)(C類)真題及答案
- 解析2025年多媒體應(yīng)用設(shè)計(jì)師考試試題及答案清單
- 清晰理解2025年網(wǎng)絡(luò)規(guī)劃設(shè)計(jì)師考試試題及答案
- 計(jì)算機(jī)考試信息管理技術(shù)應(yīng)用試題及答案
- 數(shù)學(xué)三考研試題及答案
- 深度分析軟件評(píng)測(cè)師試題及答案
- 2025年考試多媒體設(shè)計(jì)師試題與解答
- 軟件測(cè)試中的團(tuán)隊(duì)協(xié)作技巧試題及答案
- 四級(jí)考試口語試題及答案
- 社會(huì)服務(wù)的變革與發(fā)展中級(jí)考試試題及答案
- 2025年成都市中考?xì)v史試題卷(含答案)
- 建設(shè)工程法規(guī)考試題真題及答案
- 中國鹽業(yè)集團(tuán)有限公司所屬企業(yè)招聘筆試題庫2025
- 2024年江蘇省泰興市事業(yè)單位公開招聘教師崗考試題帶答案分析
- Q-GDW 10393.1-2024 變電站設(shè)計(jì)規(guī)范-第1部分:35kV變電站
- (人教2024版)英語七下期末全冊(cè)分單元總復(fù)習(xí)課件(新教材)
- 2025年二年級(jí)語文期末復(fù)習(xí)計(jì)劃
- 2025年市場(chǎng)營銷專業(yè)人才考核試題及答案
- 防范惡劣天氣安全教育
- 第七章郵輪游客投訴心理及處理技巧46課件
- 2025-2030年全球及中國槐糖脂行業(yè)市場(chǎng)現(xiàn)狀供需分析及投資評(píng)估規(guī)劃分析研究報(bào)告
評(píng)論
0/150
提交評(píng)論