Java語(yǔ)言程序設(shè)計(jì) 課件 第11、12章 記錄、枚舉和注解類型;泛型與集合_第1頁(yè)
Java語(yǔ)言程序設(shè)計(jì) 課件 第11、12章 記錄、枚舉和注解類型;泛型與集合_第2頁(yè)
Java語(yǔ)言程序設(shè)計(jì) 課件 第11、12章 記錄、枚舉和注解類型;泛型與集合_第3頁(yè)
Java語(yǔ)言程序設(shè)計(jì) 課件 第11、12章 記錄、枚舉和注解類型;泛型與集合_第4頁(yè)
Java語(yǔ)言程序設(shè)計(jì) 課件 第11、12章 記錄、枚舉和注解類型;泛型與集合_第5頁(yè)
已閱讀5頁(yè),還剩153頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Java語(yǔ)言程序設(shè)計(jì)第11章記錄、枚舉和注解類型

1記錄類型23主要內(nèi)容Java語(yǔ)言程序設(shè)計(jì)(第4版)

2022枚舉類型注解類型Java語(yǔ)言程序設(shè)計(jì)11.1記錄類型在Java程序開(kāi)發(fā)中,我們經(jīng)常需要定義一些數(shù)據(jù)類,比如與數(shù)據(jù)庫(kù)表交互的JavaBeans類或POJO類,這些類通常使用字段表示數(shù)據(jù),然后我們要為該類定義構(gòu)造方法,為字段定義訪問(wèn)方法和修改方法。這就需要程序員編寫(xiě)大量的代碼。記錄類型從Java16開(kāi)始,如果要定義這樣的類,可以使用record關(guān)鍵字將它定義為一個(gè)記錄類型。這種數(shù)據(jù)類型提供了一種緊湊的語(yǔ)法來(lái)聲明一種主要用于保存數(shù)據(jù)的類。假設(shè)定義一個(gè)Customer記錄類型,它帶兩個(gè)字段name和address,那么該類可能需要如下定義。packagecom.boda.xy;publicrecordCustomer(Stringname,Stringaddress){//這里可以定義記錄類型的成員}這里,類型名后面是一對(duì)括號(hào),里面是字段的聲明,這相當(dāng)于定義一個(gè)構(gòu)造方法。記錄類型與其他類型一樣被編譯成類(.class)文件。對(duì)于記錄類型,編譯器將自動(dòng)添加構(gòu)造方法、equals()方法、hashCode()方法和toString()方法,并且為每個(gè)實(shí)例變量添加訪問(wèn)方法(但不提供修改方法)。程序11.1Customer.java如果我們反編譯Customer.class文件,可得到類似下面的代碼。publicfinalclassCustomerextendsjava.lang.Record{privatefinaljava.lang.Stringname;privatefinaljava.lang.Stringaddress;publicCustomer(java.lang.Stringname,java.lang.Stringaddress){/*編譯的代碼*/}publicjava.lang.Stringname()

{/*編譯的代碼*/}publicjava.lang.Stringaddress()

{/*編譯的代碼*/}publicfinaljava.lang.StringtoString()

{/*編譯的代碼*/}publicfinalinthashCode()

{/*編譯的代碼*/}publicfinalbooleanequals(java.lang.Objecto)

{/*編譯的代碼*/}可以看到,聲明的Customer類繼承了java.lang.Record類,Customer類和它的兩個(gè)成員被聲明為final,也就是記錄類型不能被繼承,成員也不能被修改。記錄類型編譯器自動(dòng)為它添加構(gòu)造方法、equals()方法、hashCode()方法和toString()方法,并且為實(shí)例變量添加訪問(wèn)方法。注意,這里的訪問(wèn)方法名為實(shí)例名,如name()、address()等,而不是getName()這種形式的。publicclassCustomerDemo{publicstaticvoidmain(String[]args){varcustomer=newCustomer("張明月","北京市海淀區(qū)");varcustomer2=newCustomer("李大海","上海市科技路20號(hào)");System.out.println("姓名:"+customer.name());System.out.println("地址:"+customer.address());

System.out.println(customer.toString());System.out.println(customer.equals(customer2));System.out.println(customer.hashCode());System.out.println(customer2.hashCode());}}程序11.2CustomerDemo.java在記錄的主體中,還可以聲明static成員、構(gòu)造方法和實(shí)例方法,例如:publicCustomer(Stringname){this(name,null);}記錄類型publicstaticStringinfo="客戶";publicstaticvoidshow(){

System.out.println("顯示:"+info);}自定義構(gòu)造方法必須明確調(diào)用帶參數(shù)構(gòu)造方法自定義靜態(tài)變量和靜態(tài)方法publicvoidshowName(){System.out.println("姓名:"+name);}記錄類型【注意】

不能在記錄類型中聲明實(shí)例變量,但可以聲明靜態(tài)變量?!咀⒁狻?/p>

記錄類型字段的訪問(wèn)器名是“屬性名()”,而不是getXxx(),例如,假設(shè)記錄類型有一個(gè)name屬性,則它的訪問(wèn)器為name(),而不是getName()。此外,記錄類型沒(méi)有修改方法,也就是沒(méi)有類似的setName()方法。實(shí)例方法在記錄體中還可以覆蓋超類Record中定義的方法,下面代碼覆蓋了toString()方法和hashCode()方法。記錄類型@OverridepublicStringtoString(){ return"姓名:"+name+",地址:"+address;} @OverridepublicinthashCode(){ returnObjects.hash(name,address);}在記錄類型中用戶還可以定義自己的方法和構(gòu)造方法,但通常不這樣做。記錄類型主要是解決用于存儲(chǔ)數(shù)據(jù)的普通類的一個(gè)常見(jiàn)問(wèn)題。總結(jié)下面對(duì)記錄類型做一簡(jiǎn)單總結(jié):記錄類型默認(rèn)繼承了java.lang.Record類,不能顯式繼承其他類。記錄類型是final的,即它不可以被繼承。每個(gè)成員變量都被加上privatefinal,對(duì)象創(chuàng)建后它們就不可變。每個(gè)成員變量都提供了public訪問(wèn)方法,如name(),但不提供修改方法。提供了帶所有參數(shù)的構(gòu)造方法、toString()方法、equals()方法和hashCode()方法。1.定義一個(gè)名為Book的記錄類型,要求它實(shí)現(xiàn)Serializable接口和Comparable接口,Book記錄包含5個(gè)字段,如下所示。idint,nameString,authorString,pricedouble,pressString編程練習(xí)Java語(yǔ)言程序設(shè)計(jì)11.2枚舉類型在實(shí)際應(yīng)用中,有些數(shù)據(jù)的取值被限定在幾個(gè)確定的值之內(nèi)。例如,一年有4個(gè)季度,一周有7天、一副紙牌有4種花色等。對(duì)這種類型的數(shù)據(jù)可以定義為枚舉類型。11.2.1枚舉類型的定義枚舉類型是一種特殊的引用類型,它的聲明和使用與類和接口有類似的地方。枚舉類型的聲明使用enum關(guān)鍵字。下面程序定義了一個(gè)名為Direction的枚舉類型:

publicenumDirection{EAST,SOUTH,WEST,NORTH;}編譯后產(chǎn)生一個(gè)Direction.class類文件枚舉類型都隱含地繼承了java.lang.Enum抽象類,Enum類又是Object類的子類,同時(shí)實(shí)現(xiàn)了Comparable接口。每個(gè)枚舉類型都包含了若干方法,下面是一些常用的。

staticE[]values()

staticEvalueOf(Stringname)

finalintcompareTo(Eo)

finalStringname()

finalintordinal()11.2.2枚舉類型的方法publicstaticvoidmain(String[]args){//聲明一個(gè)枚舉類型變量,并用一個(gè)枚舉賦值varleft=Direction.WEST;System.out.println(left);//輸出:WEST//輸出每個(gè)枚舉對(duì)象及序號(hào)for(Directiond:Direction.values()){System.out.println(()+",序號(hào)"+d.ordinal());}}程序11.4DirectionDemo.java枚舉類型有一個(gè)特別實(shí)用的特性,它可以在switch語(yǔ)句中使用。java.time.DayOfWeek是一個(gè)枚舉類型,其中包括一周的7天,分別為MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY和SUNDAY,序號(hào)從0到6。EnumSwitch.java程序在switch結(jié)構(gòu)中使用DayOfWeek枚舉。11.2.3枚舉在switch中的應(yīng)用publicstaticvoiddescribe(DayOfWeekday){switch(day){caseMONDAY->System.out.println("Mondaysarebad.");caseFRIDAY->System.out.println("Fridaysarebetter.");caseSATURDAY,SUNDAY->System.out.println("Weekendsarebest.");default->System.out.println("Midweekdaysareso-so.");}}程序11.5EnumSwitch.javapublicstaticvoidmain(String[]args){varfirstDay=DayOfWeek.MONDAY;describe(firstDay);varthirdDay=DayOfWeek.WEDNESDAY;describe(thirdDay);varseventhDay=DayOfWeek.SUNDAY;describe(seventhDay);}在枚舉類型的聲明中,除了枚舉常量外還可以聲明構(gòu)造方法,成員變量和其他方法。下面程序定義了Color枚舉,它包含4種顏色。11.2.4枚舉類型的構(gòu)造方法publicenumColor{

RED("紅色",1),GREEN("綠色",2),WHITE("白色",3),YELLOW("黃色",4);

//成員變量privateStringname;privateintindex;

//構(gòu)造方法privateColor(Stringname,intindex){=name;this.index=index;

}程序11.6Color.java

//普通方法publicstaticStringgetName(intindex){for(Colorc:Color.values()){if(c.getIndex()==index){return;

}

}returnnull;

}//getter和setter方法publicStringgetName(){returnname;

}publicvoidsetName(Stringname){=name;

}publicintgetIndex(){returnindex;

}publicvoidsetIndex(intindex){this.index=index;

}

//覆蓋方法@OverridepublicStringtoString(){return+"_"+this.index;

}publicstaticvoidmain(String[]args){Colorc=Color.RED;//自動(dòng)調(diào)用構(gòu)造方法System.out.println(c.toString());//輸出:1-紅色

}Java語(yǔ)言程序設(shè)計(jì)11.3注解類型注解以結(jié)構(gòu)化的方式為程序元素提供信息,這些信息能夠被外部工具(編譯器、解釋器等)自動(dòng)處理。注解類型注解有許多用途,其中包括:

為編譯器提供信息。

編譯時(shí)或部署時(shí)處理。

運(yùn)行時(shí)處理。區(qū)分注解類型和注解注解類型是一種特殊的接口類型,像使用類一樣,要使用注解必須先定義注解類型(也可以使用語(yǔ)言本身提供的注解類型)。11.3.1注解概述注解是注解類型的一個(gè)實(shí)例。就像接口一樣,注解類型也有名稱和成員。注解中包含的信息采用“鍵/值”對(duì)的形式,可以有零或多個(gè)“鍵/值”對(duì),并且每個(gè)鍵有一個(gè)特定類型。它可以是一個(gè)Stirng、int或其他Java類型。沒(méi)有“鍵/值”對(duì)的注解類型稱作標(biāo)記注解類型。如果注解只需要一個(gè)“鍵/值”對(duì),則稱為單值注解類型。11.3.1注解概述在Java程序中為程序元素標(biāo)注注解的語(yǔ)法如下:

@AnnotationType或者

@AnnotationType(elementValuePairs)對(duì)沒(méi)有默認(rèn)值的元素,都應(yīng)該以name=value的形式對(duì)元素初始化。如果注解類型是標(biāo)記注解類型(無(wú)元素),或者所有的元素都具有默認(rèn)值,那么就可以省略初始化器列表。11.3.1注解概述如果注解類型只有一個(gè)元素,可以使用縮略的形式對(duì)注解元素初始化。例如,假設(shè)注解類型Copyright只有一個(gè)String類型的元素,用它注解程序元素時(shí)就可以寫(xiě)作:

@Copyright("copyright2010-2015")11.3.1注解概述可以給Java包、類型(類、接口、枚舉)、構(gòu)造方法、方法、成員變量、參數(shù)及局部變量進(jìn)行標(biāo)注。例如,可以給一個(gè)Java類進(jìn)行標(biāo)注,以便阻止javac程序可能發(fā)出的警告,也可以對(duì)一個(gè)要覆蓋的方法進(jìn)行標(biāo)注,讓編譯器知道你是要覆蓋這個(gè)方法而不是重載它。這里介紹Java語(yǔ)言規(guī)范中定義的3個(gè)注解類型,它們是供編譯器使用的。它們定義在java.lang包中,分別為@Override@Deprecated@SuppressWarnings11.3.2標(biāo)準(zhǔn)注解@Override是一個(gè)標(biāo)記注解類型,可以用在一個(gè)方法的聲明中,它告訴編譯器這個(gè)方法要覆蓋父類中的某個(gè)方法。使用該注解可以防止程序員在覆蓋某個(gè)方法時(shí)出錯(cuò)。例如,考慮下面的Parent類:

classParent{

publicdoublecalculate(doublex,doubley){

returnx*y;

}}假設(shè)現(xiàn)在要擴(kuò)展Parent類,并覆蓋它的calculate()方法。下面是Parent類的一個(gè)子類:

classChildextendsParent{

publicintcalculate(intx,inty){

return(x+1)*y;

}}Child類可以編譯。然而,Child類中的calculate()方法并沒(méi)有覆蓋Parent中的方法,因?yàn)樗膮?shù)是2個(gè)int型,而不是2個(gè)double型。使用Override注解就可以很容易防止這類錯(cuò)誤。每當(dāng)你想要覆蓋一個(gè)方法時(shí),就在這個(gè)方法前聲明Override注解類型:classChildextendsParent{

@Override

publicintcalculate(intx,inty){

return(x+1)*y;

}}@Deprecated是一個(gè)標(biāo)記注解類型,可以應(yīng)用于某個(gè)方法或某個(gè)類型,指明方法或類型已被棄用。警告代碼用戶不應(yīng)該使用或者覆蓋該方法,或者不該使用或擴(kuò)展該類型。一個(gè)方法或類型被標(biāo)記棄用通常是因?yàn)橛辛烁玫姆椒ɑ蝾愋汀?.@Deprecated注解下面代碼使用了Deprecated注解。@DeprecatedpublicvoidbadMethod(){

System.out.println("Deprecated");

}

publicstaticvoidmain(String[]args){

DeprecatedDemo

dd=newDeprecatedDemo();

dd.badMethod();}在Eclipse中棄用的方法加刪除線調(diào)用被棄用的方法也加刪除線@SuppressWarnings注解指示編譯器阻止某些類型的警告,具體警告類型可以用初始化該注解的字符串來(lái)定義。該注解可應(yīng)用于類型、構(gòu)造方法、方法、成員變量、參數(shù)以及局部變量。它的用法是傳遞一個(gè)String數(shù)組,其中包含需要阻止的警告。語(yǔ)法如下:

SuppressWarnings(value={string-1,…,string-n})3.@SuppressWarnings注解以下是SuppressWarnings注解的常用有效參數(shù):unchecked,未檢查的轉(zhuǎn)換警告。deprecation,使用了不推薦使用的方法的警告。serial,實(shí)現(xiàn)Serializable接口但沒(méi)有定義serialVersionUID常量的警告。rawtypes,如果使用舊的語(yǔ)法創(chuàng)建泛型類對(duì)象時(shí)發(fā)出的警告。finally,任何finally子句不能正常完成的警告。fallthrough,switch塊中某個(gè)case后沒(méi)有break語(yǔ)句的警告。3.@SuppressWarnings注解下面程序阻止了代碼中出現(xiàn)的幾種編譯警告。@SuppressWarnings(value={"unchecked","serial","deprecation"})publicclassSuppressWarningDemoimplementsSerializable{publicstaticvoidmain(String[]args){Dated=newDate();

System.out.println(d.getDay());ListmyList=newArrayList();//該語(yǔ)句仍然有警告

myList.add("one");

myList.add("two");

myList.add("three");

System.out.println(myList);}}程序11.7SuppressWarningDemo.java用戶也可以定義注解類型。注解類型的定義與接口類型的定義類似。注解類型的定義使用interface關(guān)鍵字,前面加上@符號(hào)。

public@interfaceCustomAnnotation{

//元素或?qū)傩月暶?/p>

}在注解類型中聲明的方法稱為注解類型的元素,它的聲明類似于接口中的方法聲明,沒(méi)有方法體,但有返回類型。11.3.3定義注解類型元素的類型有一些限制,如只能是基本類型、String、枚舉類型、其他注解類型等,并且元素不能聲明任何參數(shù)。在定義注解時(shí)可以使用default關(guān)鍵字為元素指定默認(rèn)值。例如:

public@interfaceVersion{

intmajor()default1;

intminor()default0;}11.3.3定義注解類型Version注解類型可以用來(lái)標(biāo)注類和接口,也可以供其他注解類型使用。例如,可以用它來(lái)重新定義ClassInfo注解類型:

public@interfaceClassInfo{Stringcreated();Stringauthor();StringlastModified();

Versionversion();}11.3.3定義注解類型注解類型中也可以沒(méi)有元素,這樣的注解稱為標(biāo)記注解(markerannotation),這與標(biāo)記接口類似。例如,下面定義了一個(gè)標(biāo)記注解類型Preliminary:public@interfacePreliminary{}11.3.3定義注解類型如果注解類型只有一個(gè)元素,這個(gè)元素應(yīng)該命名為value。例如,Copyright注解類型只有一個(gè)String類型的元素,則其應(yīng)該定義為:

public@interfaceCopyright{Stringvalue();}這樣,在為程序元素注解時(shí)就可以不需要指定元素名稱,而采用一種縮略的形式:

@Copyright("flyingdragoncompany")11.3.3定義注解類型1.定義一個(gè)名為Product記錄類型表示商品信息,它的UML圖如圖11-1所示。要求為該記錄類型定義一個(gè)僅帶id參數(shù)的構(gòu)造方法,覆蓋父類的equals()方法和hashCode()方法,為保證hashCode()方法和equals()方法兼容的,請(qǐng)使用Objects類的hash()方法和equals()。覆蓋父類的toString()方法,要求當(dāng)調(diào)用該方法是輸出Product各屬性信息。編寫(xiě)程序測(cè)試Product記錄類型所有方法的使用。編程作業(yè)2.

定義一個(gè)名為TrafficLight的enum類型,它包含三個(gè)常量:GREEN、RED和YELLOW表示交通燈的三種顏色。通過(guò)values()方法和ordinal()方法循環(huán)并打印每一個(gè)值及其順序值。編寫(xiě)一個(gè)switch語(yǔ)句,為TrafficLight的每個(gè)常量輸出有關(guān)信息。編程作業(yè)Java語(yǔ)言程序設(shè)計(jì)第12章泛型與集合

1泛型23主要內(nèi)容Java語(yǔ)言程序設(shè)計(jì)(第4版)

2022集合框架List接口及實(shí)現(xiàn)類45Set接口及實(shí)現(xiàn)類Queue接口及實(shí)現(xiàn)類6案例:用集合存儲(chǔ)、遍歷員工記錄7Map接口及實(shí)現(xiàn)類89Collections類案例:用Map統(tǒng)計(jì)單詞數(shù)量Java語(yǔ)言程序設(shè)計(jì)12.1泛型泛型是類和接口的一種擴(kuò)展機(jī)制,主要實(shí)現(xiàn)參數(shù)化類型機(jī)制。使用泛型,程序員可以編寫(xiě)更安全的程序。概述泛型是Java5引進(jìn)的新特征,泛型被廣泛應(yīng)用在Java集合API中,在Java集合框架中大多數(shù)的類和接口都是泛型類型?;仡櫼幌?,我們?cè)?.5節(jié)中定義了一個(gè)整數(shù)棧類IntStack,該類使用Integer作為棧的元素,這就限制了該類只能對(duì)Integer元素操作。12.1.1泛型類如果要使這個(gè)棧類更具有通用性,我們可以使用Object作為棧的元素,因?yàn)镺bject類是所有類的超類,所以O(shè)bject可以引用任何對(duì)象類型。然而,這種做法無(wú)法提供類型的安全性,在進(jìn)行類型轉(zhuǎn)換時(shí)可能發(fā)生類型不匹配異常。使用泛型就可以提高類型安全性,因?yàn)椋梢允诡愋娃D(zhuǎn)換自動(dòng)地、隱式地進(jìn)行。所謂泛型(generics)就是帶一個(gè)或多個(gè)類型參數(shù)(typeparameter)的類或接口。對(duì)于上述討論的對(duì)象棧,可以使用泛型定義。12.1.1泛型類為了簡(jiǎn)單,下面先定義一個(gè)泛型Node類表示節(jié)點(diǎn),類型參數(shù)T表示節(jié)點(diǎn)中存放的數(shù)據(jù)值類型。具體代碼如程序12.1所示。publicclassNode<T>{privateTdata;//泛型成員,T可以是任何引用類型publicNode(){}//默認(rèn)構(gòu)造方法publicNode(Tdata){//帶參數(shù)構(gòu)造方法this.data=data;}publicTget(){//訪問(wèn)方法定義returndata;}程序12.1Node.javapublicvoidset(Tdata){//修改方法定義this.data=data;}//顯示類型名publicvoidshowType(){ System.out.println("T的類型是:"+data.getClass().getName());}}泛型類型的使用與方法調(diào)用類似,方法調(diào)用需向方法傳遞參數(shù),使用泛型需傳遞一個(gè)類型參數(shù),即用某個(gè)具體的類型替換T。例如,如果要在Node對(duì)象中存放Integer對(duì)象,就需要在創(chuàng)建Node對(duì)象時(shí)為其傳遞Integer類型參數(shù)。12.1.1泛型類要實(shí)例化泛型類對(duì)象,也使用new運(yùn)算符,但在類名后面需加上要傳遞的具體類型。Node<Integer>

intNode=newNode<Integer>();一旦創(chuàng)建了intNode對(duì)象,就可以調(diào)用set()方法設(shè)置其中的Integer對(duì)象,如下代碼所示。

publicstaticvoidmain(String[]args){Node<Integer>intNode=newNode<Integer>();intNode.set(Integer.valueOf(999));System.out.println(intNode.get());intNode.showType();}由于編譯器能夠從上下文中推斷出泛型參數(shù)的類型,所以從JavaSE7開(kāi)始,在創(chuàng)建泛型類型時(shí)可使用菱形語(yǔ)法(diamond),即僅用一對(duì)尖括號(hào)(<>),上述創(chuàng)建intNode的語(yǔ)句可以寫(xiě)成:Node<Integer>intNode=newNode<>();12.1.1泛型類按照約定,類型參數(shù)名使用單個(gè)大寫(xiě)字母表示。常用的類型參數(shù)名有:E表示元素,K表示鍵,N表示數(shù)字,T表示類型,V表示值等。需要注意,泛型可能具有多個(gè)類型參數(shù),但在類或接口的聲明中,每個(gè)參數(shù)名必須是唯一的。與類一樣,接口也可以聲明為泛型接口,即接口也可以帶參數(shù),例如,下面的Readable接口使用泛型類型作為其read()方法的參數(shù):publicinterfaceReadble<T>{voidread(Tt);}12.1.2泛型接口類實(shí)現(xiàn)這個(gè)接口有三種方法。

第一個(gè)是指定類中的泛型類型。下面的具體類說(shuō)它只處理Book。這使得它可以用一個(gè)Book參數(shù)聲明read()方法:publicclassIntelligentRobotimplementsReadable<Book>{publicvoidread(Bookb){}}12.1.2泛型接口下一種方法是創(chuàng)建一個(gè)泛型類。下面的具體類允許調(diào)用者指定泛型的類型:publicclassIntelligentRobot<U>implementsReadable<U>{publicvoidread(Ut){}}在本例中,類型參數(shù)可以被命名為任何名稱,包括T。我們?cè)诶又惺褂昧薝,這樣就不會(huì)混淆T指的是什么。12.1.2泛型接口最后一種方法是不使用泛型。這是編寫(xiě)代碼的老方法。它產(chǎn)生一個(gè)編譯器警告Readable是一個(gè)原始類型,但它能夠編譯。這里的read()方法有一個(gè)Object參數(shù),因?yàn)榉盒皖愋蜎](méi)有定義:publicclassIntelligentRobotimplementsReadable{publicvoidread(Objecto){}}12.1.2泛型接口泛型接口也可帶有多個(gè)類型參數(shù)。下面的Entry是泛型接口,帶兩個(gè)類型參數(shù)。12.1.2泛型接口publicinterfaceEntry<K,V>{publicKgetKey();publicVgetValue();}publicclassPair<K,V>implementsEntry<K,V>{privateKkey;privateVvalue;publicPair(Kkey,Vvalue){//構(gòu)造方法this.key=key;this.value=value;}程序12.2Pair.javapublicvoidsetKey(Kkey){this.key=key;}publicKgetKey(){returnkey;}publicvoidsetValue(Vvalue){this.value=value;}publicVgetValue(){returnvalue;}}下面語(yǔ)句創(chuàng)建兩個(gè)Pair類實(shí)例:Pair<String,Integer>p1=newPair<>("twenty-two",22);Pair<String,String>p2=newPair<>("china","Beijing");泛型方法(genericmethod)是帶類型參數(shù)的方法。類的成員方法和構(gòu)造方法都可以定義為泛型方法。泛型方法的定義與泛型類型的定義類似,但類型參數(shù)的作用域僅限于聲明的方法和構(gòu)造方法內(nèi)。泛型方法可以定義為靜態(tài)的和非靜態(tài)的。12.1.3泛型方法下面的MathUtils類中定義兩個(gè)static的泛型方法swap()和compare()。swap()方法用于交換任何數(shù)組中兩個(gè)元素(數(shù)組元素類型不是基本類型),compare()方法用于比較兩個(gè)泛型類Pair對(duì)象的參數(shù)K和V是否相等。特別注意,對(duì)于泛型方法必須在方法返回值前指定泛型,如<K,V>。publicclassMathUtils{publicstatic<T>voidswap(T[]array,inti,intj){Ttemp=array[i];array[i]=array[j];array[j]=temp;}publicstatic<K,V>booleancompare(Pair<K,V>p1,Pair<K,V>p2){returnp1.getKey().equals(p2.getKey())&&p1.getValue().equals(p2.getValue());}程序12.3MathUtils.javapublicstaticvoidmain(String[]args){Integer[]numbers={1,3,5,7};MathUtils.swap(numbers,0,3);for(Integern:numbers){System.out.println(n+"");//輸出:7351}Pair<Integer,String>p1=newPair<>(1,"apple");Pair<Integer,String>p2=newPair<>(2,"orange");//調(diào)用泛型方法booleansame=MathUpare(p1,p2);System.out.println(same);//輸出:false}泛型類型本身是一個(gè)Java類型,就像java.lang.String和java.time.LocalDate一樣,為泛型類型傳遞不同的類型參數(shù)會(huì)產(chǎn)生不同的類型。例如,下面list1和list2就是不同的類型對(duì)象。

List<Object>list1=newArrayList<Object>();List<String>list2=newArrayList<String>();12.1.4通配符(?)的使用這里L(fēng)ist和ArrayList是泛型接口和泛型類。盡管String是Object的子類,但List<String>與List<Object>卻沒(méi)有關(guān)系,List<String>并不是List<Object>的子類型。因此,把一個(gè)List<String>對(duì)象傳遞給一個(gè)需要List<Object>對(duì)象的方法,將會(huì)產(chǎn)生一個(gè)編譯錯(cuò)誤。請(qǐng)看下面代碼。12.1.4通配符(?)的使用publicstaticvoidprintList(List<Object>list){for(Objectelement:list){

System.out.println(element);}}該方法的功能是打印傳遞給它的列表的所有元素。如果傳遞給該方法一個(gè)List<String>對(duì)象,將發(fā)生編譯錯(cuò)誤。如果要使上述方法可打印任何類型的列表,可將其參數(shù)類型修改為L(zhǎng)ist<?>,如下所示:publicstaticvoidprintList(List<?>list){for(Objectelement:list){

System.out.println(element);}}這里,問(wèn)號(hào)(?)就是通配符,它表示該方法可接受元素是任何類型的List對(duì)象。12.1.4通配符(?)的使用publicclassWildCardDemo{publicstaticvoidprintList(List<?>list){ for(Objectelement:list){ System.out.println(element); }}程序12.4WildCardDemo.javapublicstaticvoidmain(String[]args){ varmyList=newArrayList<String>(); myList.add("cat"); myList.add("dog"); myList.add("horse");printList(myList);}有時(shí)需要限制傳遞給類型參數(shù)的類型種類,例如,要求一個(gè)方法只接受Number類或其子類的實(shí)例,這就需要使用有界類型參數(shù)(boundedtypeparameter)。12.1.5有界類型參數(shù)有界類型分為上界和下界,上界用extends指定,下界用super指定。上界用extends指定,例如,List<?extendsNumber>,Number或Number的子類型下界用super指定,例如,List<?superInteger>,Integer或Integer的超類型publicstaticdoublegetAverage(List<?extendsNumber>numberList){ vartotal=0.0; for(varnumber:numberList){ total+=number.doubleValue(); } returntotal/numberList.size();}程序12.5BoundedTypeDemo.javapublicstaticvoidmain(String[]args){

varintegerList=newArrayList<Integer>(); integerList.add(3); integerList.add(30); integerList.add(300); System.out.println(getAverage(integerList));//輸出:111.0

vardoubleList=newArrayList<Double>(); doubleList.add(5.5); doubleList.add(55.5); System.out.println(getAverage(doubleList));//輸出:30.5當(dāng)實(shí)例化泛型類型時(shí),編譯器使用一種叫類型擦除(typeerasure)的技術(shù)轉(zhuǎn)換這些類型。在編譯時(shí),編譯器將清除類和方法中所有與類型參數(shù)有關(guān)的信息。類型擦除可讓使用泛型的Java應(yīng)用程序與之前不使用泛型類型的Java類庫(kù)和應(yīng)用程序兼容。2.1.6類型擦除例如,Node<Integer>被轉(zhuǎn)換成Node,它稱為源類型(rawtype)。源類型是不帶任何類型參數(shù)的泛型類或接口名。這說(shuō)明在運(yùn)行時(shí)找不到泛型類使用的是什么類型。下面的操作是不可能的。publicclassMyClass<E>{publicstaticvoidmyMethod(Objectitem){if(iteminstanceofE){//編譯錯(cuò)誤…}

Eitem2=newE();//編譯錯(cuò)誤E[]iArray=newE[10];//編譯錯(cuò)誤Eobj=(E)newObject();//非檢查的造型警告}}Java語(yǔ)言程序設(shè)計(jì)12.2集合框架在編寫(xiě)面向?qū)ο蟮某绦驎r(shí),經(jīng)常要用到一組類型相同的對(duì)象??梢允褂脭?shù)組來(lái)集中存放這些類型相同的對(duì)象,但數(shù)組一經(jīng)定義便不能改變大小。因此,Java提供了一個(gè)集合框架(collectionsframework),該框架定義了一組接口和類,使處理對(duì)象組更容易。集合框架集合是指集中存放一組對(duì)象的一個(gè)對(duì)象。集合相當(dāng)于一個(gè)容器。集合能夠幫助Java程序員輕松地管理對(duì)象。Java集合框架由兩種類型構(gòu)成,一個(gè)是Collection,另一個(gè)是Map。Collection對(duì)象用于存放一組對(duì)象,Map對(duì)象用于存放一組“關(guān)鍵字/值”的對(duì)象。Collection<E>接口是所有集合類型的根接口,它繼承了Iterable<E>接口,它有三個(gè)子接口:Set接口、List接口和Queue接口。Collection接口定義了集合操作的常用方法??梢院?jiǎn)單分為以下幾類:基本操作、批量操作、數(shù)組操作和流操作。集合框架實(shí)現(xiàn)基本操作的方法添加元素、刪除指定元素、返回集合中元素的個(gè)數(shù)、返回集合的迭代器對(duì)象。1.基本操作booleanadd(Ee):向集合中添加元素e。booleanremove(Objecto):從集合中刪除指定的元素o。booleancontains(Objecto):返回集合中是否包含指定的元素o。booleanisEmpty():返回集合是否為空,即不包含元素。intsize():返回集合中包含的元素個(gè)數(shù)。Iteratoriterator():返回包含所有元素的迭代器對(duì)象。下面的方法可實(shí)現(xiàn)集合的批量操作。booleanaddAll(Collection<?extendsE>c):將集合c中的所有元素添加到當(dāng)前集合中。booleanremoveAll(Collection<?>c):從當(dāng)前集合中刪除c中的所有元素。defaultbooleanremoveIf(Predicate<?superE>filter)booleancontainsAll(Collection<?>c):返回當(dāng)前集合是否包含c中的所有元素。booleanretainAll(Collection<?>c):在當(dāng)前集合中只保留指定集合c中的的元素,其他元素刪除。

voidclear():將集合清空。

2.批量操作下面方法可以將集合元素轉(zhuǎn)換成數(shù)組元素。Object[]toArray():返回包含集合中所有元素的對(duì)象數(shù)組。

<T>T[]toArray(T[]a):返回包含集合中所有元素的數(shù)組,返回?cái)?shù)組的元素類型是指定的數(shù)組類型。3.數(shù)組操作設(shè)c是一個(gè)Collection對(duì)象,下面的代碼將c中的對(duì)象轉(zhuǎn)換成一個(gè)新的Object數(shù)組,數(shù)組的長(zhǎng)度與集合c中的元素個(gè)數(shù)相同。Object[]a=c.toArray();Java語(yǔ)言程序設(shè)計(jì)12.3List接口及實(shí)現(xiàn)類List接口是Collection的子接口,它實(shí)現(xiàn)一種線性表的數(shù)據(jù)結(jié)構(gòu)。存放在

List中的所有元素都有一個(gè)下標(biāo)(從0開(kāi)始),可以通過(guò)下標(biāo)訪問(wèn)List中的元素。List中可以包含重復(fù)元素。List接口的實(shí)現(xiàn)類包括ArrayList、LinkedList、Vector和Stack。概述北京上海廣州bigCities012List接口除繼承Collection的方法外,還定義了一些自己的方法。使用這些方法可以實(shí)現(xiàn)定位訪問(wèn)、查找、迭代和返回子線性表。List的常用方法如下。12.3.1List的操作booleanadd(Ee):向集合中添加元素e。voidadd(intindex,Eelement):將指定元素插入到指定下標(biāo)處。Eget(intindex):返回指定下標(biāo)處的元素。Eset(intindex,Eelement):修改指定下標(biāo)處的元素。static

<E>

List<E>

of?(E...

elements):返回包含任意數(shù)量元素的不可修改列表。該方法還接受單個(gè)數(shù)組作為參數(shù)。結(jié)果列表的元素類型將是數(shù)組的元素類型,列表的大小等于數(shù)組的長(zhǎng)度。Eremove(intindex):刪除指定下標(biāo)處的元素。intindexOf(Objecto):查找指定對(duì)象第一次出現(xiàn)的位置。intlastIndexOf(Objecto):查找指定對(duì)象最后一次出現(xiàn)的位置。List<E>subList(intfrom,intto):返回從from到to元素的一個(gè)子線性表。12.3.1List的操作下面代碼使用List的of()方法創(chuàng)建一個(gè)不可修改的List對(duì)象,對(duì)不可修改的對(duì)象調(diào)用修改方法將拋出運(yùn)行時(shí)異常。List<String>nameList=List.of("趙","錢","孫","李");System.out.println(nameList);//輸出:[趙,錢,孫,李]//nameList.add("周");//nameList.set(1,"吳");//nameList.remove("李");System.out.println(nameList.indexOf("孫"));//輸出:2產(chǎn)生運(yùn)行時(shí)異常ArrayList類實(shí)際上實(shí)現(xiàn)了一個(gè)變長(zhǎng)的對(duì)象數(shù)組,其元素可以動(dòng)態(tài)地增加和刪除。它的定位訪問(wèn)時(shí)間是常量時(shí)間。12.3.2ArrayList類ArrayList的構(gòu)造方法如下:publicArrayList()public

ArrayList(Collectionc)public

ArrayList(intinitialCapacity)下列代碼創(chuàng)建一個(gè)ArrayList對(duì)象并向其中插入幾個(gè)元素,并使用ArrayList的有關(guān)方法對(duì)它操作。varcities=newArrayList<String>();cities.add("北京");cities.add("上海");cities.add("廣州");System.out.println(cities.size());cities.add(1,"倫敦");cities.set(1,"紐約");System.out.println(cities.contains("北京"));System.out.println(cities);System.out.println(cities.indexOf("巴黎"));遍歷集合中的元素有多種方法:用簡(jiǎn)單的for循環(huán)、用增強(qiáng)的for循環(huán)和用Iterator迭代器對(duì)象。12.3.3遍歷集合元素1.使用for循環(huán)使用for循環(huán)可以遍歷集合中的每個(gè)元素。for(var

i=0;i<cities.size();i++){

System.out.print(cities.get(i)+"");}2.使用增強(qiáng)的for循環(huán)使用增強(qiáng)的for循環(huán)不但可以遍歷數(shù)組的每個(gè)元素,還可以遍歷集合中的每個(gè)元素。下面的代碼打印集合的每個(gè)元素:for(varcity:cities){

System.out.println(city);}12.3.3遍歷集合元素上述代碼的含義是:依次將集合cities中的每個(gè)對(duì)象存儲(chǔ)到city變量中,然后打印輸出。如果只是簡(jiǎn)單輸出每個(gè)元素,可以調(diào)用集合對(duì)象的forEach()方法,給它傳遞一個(gè)System.out:println方法引用。

cities.forEach(System.out::println);12.3.3遍歷集合元素3.使用迭代器迭代器是一個(gè)可以遍歷集合中每個(gè)元素的對(duì)象。調(diào)用集合對(duì)象的iterator()方法可以得到Iterator對(duì)象,再調(diào)用Iterator對(duì)象的方法就可以遍歷集合中的每個(gè)元素。Iterator接口定義了如下3個(gè)方法。booleanhasNext():返回迭代器中是否還有對(duì)象。Enext():返回迭代器中下一個(gè)對(duì)象。voidremove():刪除迭代器中的當(dāng)前對(duì)象。12.3.3遍歷集合元素Iterator使用一個(gè)內(nèi)部指針,開(kāi)始它指向第一個(gè)元素的前面。如果在指針的后面還有元素,hasNext()方法返回true。調(diào)用next()方法,指針將移到下一個(gè)元素,并返回該元素。remove()方法將刪除指針?biāo)傅脑?。假設(shè)myList是ArrayList的一個(gè)對(duì)象,要訪問(wèn)myList中的每個(gè)元素,可以按下列方法實(shí)現(xiàn):Iteratoriterator=myList.iterator();//得到迭代器對(duì)象while(iterator.hasNext()){System.out.println(iterator.next());}使用Iterator也可以用for循環(huán)訪問(wèn)集合元素。for(Iteratoriterator=myList.iterator();iterator.hasNext();){System.out.println(iterator.next());}4.雙向迭代器List還提供了listIterator()方法返回ListIterator對(duì)象。它可以從前后兩個(gè)方向遍歷線性表中元素,在迭代中修改元素以及獲得元素的當(dāng)前位置。ListIterator是Iterator的子接口,它不但繼承了Iterator接口中的方法,還定義了自己的方法。12.3.3遍歷集合元素booleanhasPrevious():是否還有前一個(gè)元素。Eprevious():返回前一個(gè)元素。voidremove():刪除當(dāng)前元素。voidset(Eo):修改當(dāng)前元素。List<String>myList=List.of("北京","上海","廣州","深圳"); ListIterator<String>iterator=myList.listIterator();while(iterator.hasNext()){iterator.next();}//從后向前訪問(wèn)列表每個(gè)元素while(iterator.hasPrevious()){ System.out.print(iterator.previous()+"");}程序12.8IteratorDemo.javajava.util.Arrays類提供了一個(gè)asList()方法,它實(shí)現(xiàn)將數(shù)組轉(zhuǎn)換成List對(duì)象的功能,該方法的定義如下。publicstatic<T>List<T>asList(T…a)該方法提供了一個(gè)方便的從多個(gè)元素創(chuàng)建List對(duì)象的途徑,它的功能與Collection接口的toArray()方法相反。12.3.4數(shù)組轉(zhuǎn)換為L(zhǎng)ist對(duì)象String[]str={"one","two","three","four"};List<String>list=Arrays.asList(str);//將數(shù)組轉(zhuǎn)換為列表

System.out.println(list);Java語(yǔ)言程序設(shè)計(jì)12.4Set接口及實(shí)現(xiàn)類Set接口是Collection的子接口,Set接口對(duì)象類似于數(shù)學(xué)上的集合概念,其中不允許有重復(fù)的元素。Set接口沒(méi)有定義新的方法,只包含從Collection接口繼承的方法。Set接口的常用實(shí)現(xiàn)類有:HashSet類、TreeSet類和LinkedHashSet類。概述HashSet類用散列方法存儲(chǔ)元素,具有最好的存取性能,但元素沒(méi)有順序。HashSet類的構(gòu)造方法有:12.4.1HashSet類HashSet類的構(gòu)造方法有:HashSet()初始容量是16,默認(rèn)裝填因子是0.75。HashSet(Collectionc)HashSet(int

initialCapacity)varwords=newHashSet<String>();words.add("one");words.add("two");words.add("three");words.add("one");for(varw:words){System.out.print(w+"");//輸出:onetwothree}使用Set對(duì)象的批量操作方法,可以實(shí)現(xiàn)標(biāo)準(zhǔn)集合代數(shù)運(yùn)算。假設(shè)s1和s2是Set對(duì)象,下面的操作可實(shí)現(xiàn)相關(guān)的集合運(yùn)算。12.4.2用Set對(duì)象實(shí)現(xiàn)集合運(yùn)算s1.addAll(s2):實(shí)現(xiàn)集合s1與s2的并運(yùn)算。s1.retainAll(s2):實(shí)現(xiàn)集合s1與s2的交運(yùn)算。s1.removeAll(s2):實(shí)現(xiàn)集合s1與s2的差運(yùn)算。s1.containAll(s2):如果s2是s1的子集,該方法返回true。設(shè)集合中存放的元素類型為Integer。為了計(jì)算兩個(gè)集合的并、交、差運(yùn)算而又不破壞原來(lái)的集合,可以通過(guò)下面代碼實(shí)現(xiàn)。vars1=Set.of(1,2,3);vars2=Set.of(2,3,4);varunion=newHashSet<Integer>(s1);union.addAll(s2);//[1,2,3,4]varintersection=newHashSet<Integer>(s1);intersection.retainAll(s2);//[2,3]vardifference=newHashSet<Integer>(s1);difference.removeAll(s2);//[1]TreeSet實(shí)現(xiàn)一種樹(shù)集合,它使用紅-黑樹(shù)為元素排序,添加到TreeSet中的元素必須是可比較的,即元素的類必須實(shí)現(xiàn)Comparable<T>接口。它的操作要比HashSet慢。

TreeSet類的默認(rèn)構(gòu)造方法創(chuàng)建一個(gè)空的樹(shù)集合,其他構(gòu)造方法如下。12.4.3TreeSet類TreeSet(Collectionc)TreeSet(Comparatorc)varts=newTreeSet<String>();//TreeSet中的元素將自動(dòng)排序vars=newString[]{"one","two","three","four"};for(vari=0;i<s.length;i++){ts.add(s[i]);}System.out.println(ts);//輸出:[four,one,three,two]

從輸出結(jié)果中可以看到,這些字符串是按照自然順序排序的。程序12.9TreeSetDemo.java創(chuàng)建TreeSet類對(duì)象時(shí)如果沒(méi)有指定比較器對(duì)象,集合中的元素按自然順序排列。所謂自然順序(naturalorder)是指集合對(duì)象實(shí)現(xiàn)了Comparable<T>接口的compareTo()方法,對(duì)象則根據(jù)該方法排序。如果試圖對(duì)沒(méi)有實(shí)現(xiàn)Comparable<T>接口的集合元素排序,將拋出ClassCastException異常。12.4.4對(duì)象順序另一種排序方法是創(chuàng)建TreeSet對(duì)象時(shí)指定一個(gè)比較器對(duì)象,這樣,元素將按比較器的規(guī)則排序。如果需要指定新的比較規(guī)則,可以定義一個(gè)類實(shí)現(xiàn)Comparator<T>接口,然后為集合提供一個(gè)新的比較器。字符串的默認(rèn)比較規(guī)則是按字母順序比較。假如按反順序比較,可以定義一個(gè)類實(shí)現(xiàn)Comparator<T>接口,然后用該類對(duì)象作為比較器。下面的程序就可以實(shí)現(xiàn)字符串的降序排序:12.4.4對(duì)象順序String[]s={"China","England","France","America","Russia",};varts=newTreeSet<String>();for(vari=0;i<s.length;i++){ts.add(s[i]);}System.out.println(ts);//按自然順序輸出程序12.10DescSortDemo.javats=newTreeSet<String>(

newComparator<String>(){

@Overridepublicintcompare(Stringa,Stringb){returnpareTo(a);}});

for(vari=0;i<s.length;i++){

ts.add(s[i]);}System.out.println(ts);創(chuàng)建一個(gè)比較器對(duì)象Java語(yǔ)言程序設(shè)計(jì)12.5Queue接口及實(shí)現(xiàn)類Queue接口是Collection的子接口,它是以先進(jìn)先出(First-In-First-Out,F(xiàn)IFO)的方式排列其元素,一般稱為隊(duì)列(queue)。Deque接口是Queue接口的子接口,它的對(duì)象實(shí)現(xiàn)雙端隊(duì)列,ArrayDeque和LinkedList是它的兩個(gè)實(shí)現(xiàn)類。PriorityQueue實(shí)現(xiàn)的是一種優(yōu)先隊(duì)列,優(yōu)先隊(duì)列中元素的順序是根據(jù)元素的值排列的。概述Queue接口除了提供Collection的操作外,還提供了插入、刪除和檢查操作。12.5.1Queue接口和Deque接口Deque接口實(shí)現(xiàn)雙端隊(duì)列,它支持從兩端插入和刪除元素,它同時(shí)實(shí)現(xiàn)了Stack和Queue的功能。Deque接口中定義的基本操作方法,如表12-1所示。Deque接口常用方法操作類型隊(duì)首元素操作隊(duì)尾元素操作插入元素addFirst(e)offerFirst(e)addLast(e)offerLast(e)返回元素getFirst()peekFirst()getLast()peekLast()刪除元素removeFirst()pollFirstremoveLast()pollLast()Deque的常用實(shí)現(xiàn)類包括ArrayDeque類和LinkedList類,前者是

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論