第14章 抽象類和接口_第1頁
第14章 抽象類和接口_第2頁
第14章 抽象類和接口_第3頁
第14章 抽象類和接口_第4頁
第14章 抽象類和接口_第5頁
已閱讀5頁,還剩47頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

Chapter14

AbstractClassesandInterfaces

抽象類和接口2抽象類例:假設(shè)每個(gè)與形狀有關(guān)的類都定義了display方法,用來顯示具體對象的形狀。ShapeRectTriangleCircleRoundedRect此時(shí),可以利用多態(tài)性編寫代碼,用來顯示各種形狀:Shape[]shapeBody=newShape[20];shapeBody[0]=newRect();shapeBody[1]=newShape();…for(inti=0;i<20;i++){shapeBody[i].display();}3然而,由于Shape是一個(gè)抽象的概念,如果它也有display方法就不太合情理??梢宰鲆韵聨追N考慮:去掉Shape類的display方法損失了多態(tài)性的優(yōu)點(diǎn)??赡軐?dǎo)致程序出錯(cuò),如上例。將Shape類的display方法定義成空語句publicvoiddisplay(){}將Shape類的display方法定義成抽象方法abstractclassShape{ …publicabstractvoiddisplay();}當(dāng)一個(gè)類中包含了抽象的方法,此類就被認(rèn)為是一個(gè)抽象類。此時(shí)Shape就不能被實(shí)例化了,從而在編譯時(shí)就避免了采用第1種方法可能出現(xiàn)的錯(cuò)誤。4抽象類的特點(diǎn)抽象類中的方法不一定都是抽象的,抽象類中可以包含抽象的方法,也可以包含具體的方法。不能實(shí)例化抽象類例:如果Course是抽象類,則以下語句是錯(cuò)誤的

Coursec=newCourse();

但是可以聲明對Course對象的引用:

Coursex;抽象類有子類的時(shí)候,除非子類采用具體的方法替代抽象類中的全部抽象方法,否則子類本身也被自動(dòng)被認(rèn)為是抽象的。

抽象類之所以被稱之為“抽象”的,是因?yàn)槌橄箢愂÷粤艘獔?zhí)行的一種或多種特定行為的細(xì)節(jié)。5抽象類ΔGeometricObjectCircleCylinderRectangleCircle9.javaCylinder9.javapage3706說明

非抽象類(具體類)不能包含抽象方法。如果抽象父類的子類,沒有實(shí)現(xiàn)所有的抽象方法,它必須聲明為抽象的(在這個(gè)類聲明的前面加上abstract關(guān)鍵詞)。也就是說,在一個(gè)由抽象類擴(kuò)展出來的非抽象類中,所有的抽象方法都必須實(shí)現(xiàn),即使這個(gè)子類不使用它們。7說明抽象類不能用new運(yùn)算符實(shí)例化,但仍應(yīng)定義它的構(gòu)造方法,這種構(gòu)造方法將在它子類的構(gòu)造方法中被調(diào)用。例如,GeometricObject

的構(gòu)造方法在Circle

類和Rectangle

類中被調(diào)用。8說明(了解)允許聲明沒有抽象方法的抽象類。(用于定義新子類)子類可以被聲明是抽象的,即使它的父類是具體的。子類可以覆蓋它父類的方法,并將其聲明為抽象的。(當(dāng)父類方法中的實(shí)現(xiàn)在子類中無效時(shí))9說明不能用new運(yùn)算符創(chuàng)建抽象類的實(shí)例,但是,抽象類可以用作數(shù)據(jù)類型。下面的語句創(chuàng)建了一個(gè)元素是GeometricObject類型的數(shù)組:

GeometricObject[]geo=newGeometricObject[10];10接口接口比抽象類更抽象,它僅僅聲明了方法。例如:為了教學(xué),對象可能需要提供以下服務(wù):同意教授特定的課程指定課程所使用的教科書定義課程的授課提綱批準(zhǔn)特定的學(xué)生參加課程學(xué)習(xí)此時(shí)可以建立關(guān)于一個(gè)Teacher的接口:interfaceTeacher{ publicvoidagreeToTeach(Coursec); publicvoiddesignateTextbook(Textbookb,Coursec); publicsyllabusdefineSyllabus(Coursec); publicbooleanapproveEnrollmen(Students,Coursec);}11有了Teacher接口,就可以把對象的各種類指定為教師例如:可以認(rèn)為Professor能夠教學(xué),Student能夠教學(xué),一般的Person也可以教學(xué):classProfessorimplementsTeacher{ Stringname; StingemplyeeId; publicvoidagreeToTeach(Coursec){

//編寫代碼

} publicvoiddesignateTextbook(Textbookb,Coursec){ //編寫代碼

} publicsyllabusdefineSyllabus(Coursec){ //編寫代碼

} publicbooleanapproveEnrollmen(Students,Coursec){ //編寫代碼

}}12說明:通過這樣的定義,Professor類替代了Teacher接口的所有方法,因此Professor類是一個(gè)具體的類。但是如果Professor類沒有替換所有的接口,則Professor類只能看成是一個(gè)抽象的類。編譯器會(huì)要求在Professor類的前面加上abstract關(guān)鍵字。因此,實(shí)現(xiàn)接口實(shí)際上就是在創(chuàng)建抽象類的子類時(shí),給抽象方法“加上具體的內(nèi)容”。接口與抽象類的不同在于:接口只抽象行為而抽象類則要指定屬性、具體的方法和抽象的方法。13一個(gè)類可以繼承自多個(gè)接口例如:還有一個(gè)Administrator接口:interfaceAdministrator{ publicbooleanapproveNewCourse(Coursec); publichireProfessor(Professorp);}則可以指定類實(shí)現(xiàn)Teacher和Administrator接口:classProfessorimplementsTeacher,Administrator{ …}在這種情況下,類需要替代這兩個(gè)接口所定義的所有方法。14用接口實(shí)現(xiàn)多重繼承問:為什么Java不支持多重繼承?答:因?yàn)楫?dāng)一個(gè)子類從兩個(gè)以上的父類繼承下來的時(shí)候,可能會(huì)出現(xiàn)屬性和方法重復(fù)或沖突的現(xiàn)象。PersonStringnameStudentStringmajorintidProfessorStringtitleStringidProfessorStudentProfessorStudent繼承的屬性StringnameStringmajorintidStringname(重復(fù))StringtitleStringid(沖突)Professor可以講課,Student類可以聽課,為了描述能講課的學(xué)生定義了ProfessorStudent類。15多重繼承時(shí)方法也會(huì)發(fā)生沖突:classA{publicvoidf(){…}}classDextendsB,extendsC{publicvoidh(){f();g();}}classCextendsA{publicvoidg(){…}}classBextendsA{publicvoidg(){…}}

當(dāng)在D中使用f()時(shí),有B和C二條路徑到達(dá)A中的f();

在D中調(diào)用g();時(shí),無法確定是調(diào)用哪個(gè)基礎(chǔ)類的g()方法16分析:多重繼承發(fā)生問題原因之一在于屬性(數(shù)據(jù)結(jié)構(gòu))沖突,也就是存儲(chǔ)空間的沖突。由于接口不與任何存儲(chǔ)空間相關(guān)聯(lián),因此可以解決存儲(chǔ)空間沖突的問題。對于繼承的方法的沖突,當(dāng)使用接口之后,由于接口只定義了方法的抽象,沒有具體的執(zhí)行代碼,因此也不會(huì)發(fā)生代碼沖突的問題。17在此例中把與講課有關(guān)的所有要素提取出來,放入Teacher接口。此時(shí),ProfessorStudent類和Professor類都具有了講課的能力。語句格式:classProfessorStudentextendsStudentimplementsTeacher{

…}Person類Student類Professor類Teacher接口ProfessorStudent18總結(jié):一個(gè)類可以繼承自一個(gè)抽象類或具體類,以及多個(gè)接口。抽象類或具體類接口1接口2接口n…子類

子類只有將接口中聲明的所有方法,以及抽象類中所有的抽象方法都進(jìn)行定義,這個(gè)子類才能成為一個(gè)“具體”的類,才能實(shí)例化。如果你的基礎(chǔ)類可以不帶任何屬性和方法定義時(shí),可以將它定義成一個(gè)接口。只有在必須帶有屬性和方法定義的時(shí)候,才采用抽象類或具體類。接口繼承自其他接口利用關(guān)鍵字extends,接口可以繼承其他接口例如:publicinterfaceNewInterfaceextendsInterface1,Interface2{}1920例2Δ

使用GeometricObject類目標(biāo):編寫程序,創(chuàng)建兩個(gè)幾何對象,一個(gè)圓和一個(gè)矩形。調(diào)用equalArea方法檢查兩個(gè)對象是否有相同的面積,調(diào)用displayGeometricObject方法顯示這些對象的信息。TestGeometricObjectpage37321輸出結(jié)果:Thetwoobjectshavethesamearea?false[Circle]radius=5.0Theareais78.53981633974483Theperimeteris31.41592653589793[Rectangle]width=5.0andheight=3.0Theareais15.0Theperimeteris16.022接口接口(interface)是一種與類相似的結(jié)構(gòu),只包含常量和抽象方法。接口在許多方面與抽象類相近,但是抽象類出來包含常量和抽象方法之外,還可以包含變量和具體方法。為了區(qū)分接口和類,Java采用以下語法聲明接口:publicinterfaceInterfaceName{constantdeclarations;/*常量聲明*/methodsignatures;/*方法頭標(biāo)志*/}23接口是一個(gè)特殊的類

在Java中,接口被看成是特殊的類。和類一樣,每個(gè)接口編譯為獨(dú)立的字節(jié)碼文件。接口的使用與抽象類很相似。例如:不能使用new操作符創(chuàng)建一個(gè)接口的實(shí)例;可以使用接口作為變量的數(shù)據(jù)類型等。24接口與抽象類

接口中的數(shù)據(jù)必須是常量;抽象類中的數(shù)據(jù)可以有常量,也可以有變量。

接口中的方法只有一個(gè)頭標(biāo)志,沒有實(shí)現(xiàn)部分;抽象類中可以有抽象的方法,也可以有具體的方法。Page38425接口與抽象類在接口中,所有的數(shù)據(jù)域都是public

final

static

的,所有的方法都是public

abstract

的.由于這個(gè)原因,這些修飾可以忽略,如下所示:提示:接口中的常量能用下面的方式訪問:接口名.常量名

(例如,T1.K).

26接口與抽象類所有的類共享同一個(gè)根:Object類,但接口沒有共同的根。與類相似,接口也可以定義一個(gè)類型。一個(gè)接口類型的變量可以引用任何實(shí)現(xiàn)該接口的類的實(shí)例。如果一個(gè)類實(shí)現(xiàn)了一個(gè)接口,這個(gè)接口就類似于該類的一個(gè)父類??梢詫⒁粋€(gè)接口當(dāng)作一個(gè)數(shù)據(jù)類型使用,能夠?qū)⒔涌陬愋偷淖兞哭D(zhuǎn)換到它的子類,反過來也可以。27接口與抽象類假設(shè)c是Class2類的一個(gè)實(shí)例,則

c也是

Object,Class1,Interface1,Interface1_1,Interface1_2,Interface2_1,和Interface2_2的實(shí)例.28創(chuàng)建自定義接口?publicinterfaceEdible{

/**Describehowtoeat*/

publicStringhowToEat();

}classAnimal{

}

classChickenextendsAnimal

implementsEdible{

publicStringhowToEat(){

return"Fryit";

}

}

classTigerextendsAnimal{

}classFruitimplementsEdible{

publicStringhowToEat(){

return"Eatitfresh";

}

}

classAppleextendsFruit{

publicStringhowToEat(){

return"Makeapplecider";

}

}

classOrangeextendsFruit{

publicStringhowToEat(){

return"Makeorangejuice";

}

}Page37729創(chuàng)建自定義接口publicclassTestEdible{

publicstaticvoidmain(String[]args){

Object[]objects={newTiger(),newChicken(),newApple()};

for(inti=0;i<objects.length;i++)

showObject(objects[i]);

}

publicstaticvoidshowObject(Objectobject){

if(objectinstanceofEdible)

System.out.println(((Edible)object).howToEat());

}

}30Comparable接口//這個(gè)接口被定義在java.lang包中packagejava.lang;publicinterfaceComparable{publicintcompareTo(Objecto);}選講page37831Comparable接口compareTo方法判斷這個(gè)對象相對于給定對象o的順序,并且當(dāng)這個(gè)對象小于、等于或大于給定對象時(shí),分別返回一個(gè)負(fù)整數(shù)、0或正整數(shù)。選講32Comparable接口Java類庫中的許多類(比如,String和Date)都實(shí)現(xiàn)了Comparable接口,定義了對象的自然順序。如果你查看這些類的源代碼,你可以發(fā)現(xiàn)這一點(diǎn):

newString()instanceofStringnewString()instanceofComparablenewjava.util.Date()instanceofjava.util.Datenewjava.util.Date()instanceofComparable選講33Comparable接口//Max.java:找到兩個(gè)對象中較大的一個(gè)publicclassMax{publicstaticObjectmax(Objecto1,Objecto2){if(((Comparable)o1).compareTo(o2)>0)returno1;elsereturno2;}}為了能夠使max方法找出兩個(gè)對象中的較大者,需要為這些對象的類實(shí)現(xiàn)Comparable接口。由于o1聲明為Object類型,(Comparable)o1告訴編譯器o1轉(zhuǎn)換為Comparable類型,因而可以從o1中調(diào)用compareTo方法。34Comparable接口publicclassMax{publicstaticObjectmax(Objecto1,Objecto2){if(((Comparable)o1).compareTo(o2)>0)returno1;elsereturno2;}}調(diào)用語句1:Dated1=newDate();Dated2=newDate();Dated3=(Date)Max.max(d1,d2);由于max方法返回Object類型,因此在調(diào)用的時(shí)候,需要對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換。調(diào)用語句2:Strings1="abcdef";Strings2="abcdee";Strings3=(String)Max.max(s1,s2);35Comparable接口publicclassMax{publicstaticComparablemax(Comparableo1,Comparableo2){if(pareTo(o2)>0)returno1;elsereturno2;}}max方法的第二種寫法,與前面的代碼功能等價(jià):36舉例:Comparable接口的實(shí)現(xiàn)

目前我們不能使用max方法得到兩個(gè)Rectangle類對象中較大的一個(gè),因?yàn)镽ectangle類沒有實(shí)現(xiàn)Comparable接口。下面的例子就是在Rectangle類的基礎(chǔ)上定義一個(gè)ComparableRectangle類,使它具有矩形比較的功能。ComparableRectangle選講37舉例:Comparable接口的實(shí)現(xiàn)ComparableRectangleComparableRectanglerectangle1=newComparableRectangle(4,5);ComparableRectanglerectangle2=newComparableRectangle(3,6);System.out.println(Max.max(rectangle1,rectangle2));選講UML圖形符號說明:接口名稱及其方法名用斜體書寫。虛線和空心三角形用于指向接口。38Cloneable接口packagejava.lang;publicinterfaceCloneable{}Cloneable接口定義在java.lang包中,定義如下:選講page381

這個(gè)接口是空的,稱為標(biāo)記接口(markerinterface)。一個(gè)實(shí)現(xiàn)了Cloneable接口的類就標(biāo)記為可復(fù)制的,它的對象就可以使用Object類中定義的clone()方法實(shí)現(xiàn)克隆功能。39舉例Java中的很多類(如Date和Calendar)都實(shí)現(xiàn)了Cloneable接口。這樣,這些類的實(shí)例就能克隆。例如,下列代碼:Calendarcalendar=newGregorianCalendar(2007,2,1);CalendarcalendarCopy=(Calendar)calendar.clone();System.out.println("calendar==calendarCopyis"+(calendar==calendarCopy));System.out.println("calendar.equals(calendarCopy)is"+calendar.equals(calendarCopy));

顯示:calendar==calendarCopyisfalsecalendar.equals(calendarCopy)istrue

選講對Date而言,==用來比較引用是否相等,equals用來比較內(nèi)容是否相等。40實(shí)現(xiàn)Cloneable接口若要聲明一個(gè)實(shí)現(xiàn)Cloneable接口的自定義類,該類必須覆蓋Object類中的clone()方法。下面程序聲明了一個(gè)House類,它實(shí)現(xiàn)了Cloneable接口和Comparable接口。House選講41Shallowvs.DeepCopy

淺拷貝和深拷貝Househouse1=newHouse(1,1750.50);Househouse2=(House)house1.clone();shallowcopy選講42淺拷貝和深拷貝淺拷貝是指當(dāng)對象的字段值被拷貝時(shí),字段引用的對象不會(huì)被拷貝。例如,當(dāng)House對象被clone之后(淺拷貝),此時(shí)會(huì)創(chuàng)建一個(gè)新的House對象(House2),House2的字段值都從House1復(fù)制得到,那么house1和house2對象的whenBulit將引用同一個(gè)Date對象。深拷貝是對對象實(shí)例中字段引用的對象也進(jìn)行拷貝的一種方式。若是深拷貝,則應(yīng)創(chuàng)建一個(gè)新的House對象和一個(gè)新的Date對象,新的House對象將引用新的Date對象。簡單地說,淺拷貝只復(fù)制頂級對象,而深拷貝則復(fù)制對象及其子對象。選講43淺拷貝和深拷貝在這個(gè)例子中,若希望實(shí)現(xiàn)深拷貝,則在定義clone()方法時(shí),應(yīng)該自己寫一段代碼,在復(fù)制兩個(gè)對象的字段的同時(shí),還要考慮Date對象的創(chuàng)建。clone方法改寫如下:publicObjectclone(){try{ //java.util.Datedate=newjava.util.Date(); Objecto=super.clone(); Datedate=(Date)((House)o).getWhenBuilt().clone(); ((House)o).setWhenBuilt(date); returno;}catch(CloneNotSupportedExceptionex){returnnull;}}選講說明:需要在House.java的源程序前面增加下列語句,才能正常使用Date類:importjava.util.*;44淺拷貝和深拷貝測試的main方法如下:

publicstaticvoidmain(String[]arg){ Househouse1=newHouse(1,100.0); Househouse2=(House)house1.clone(); if(house1.whenBuilt==house2.whenBuilt) System.out.println("==true"); else System.out.println("==false");

}說明:如果運(yùn)行結(jié)果為true,則說明whenBuilt指向的是同一個(gè)對象,是淺拷貝;若結(jié)果為false,則說明whenBuilt指向的是不同的對象,是深拷貝。選講45將基本數(shù)據(jù)類型處理為對象

(包裝類WrapperClasses)Δ由于效率的原因Java中的基本數(shù)據(jù)類型不作為對象使用。然而,許多Java中的方法需要對象作為參數(shù)。(例如,集合類)Java提供了一個(gè)方法,可將基本數(shù)據(jù)類型并入對象或包裝成對象。

(例如,將int

類型包裝成Integer

類)page38646包裝類BooleanCharacterShortByteIntegerLongFloatDouble注意:包裝類沒有無參構(gòu)造方法所有包裝類對象一旦創(chuàng)建,其內(nèi)部的值就不可以再改變了。47包裝類

每一個(gè)包裝類覆蓋了Object類中定義的toString,equals,和hashCode方法。因?yàn)樗械臄?shù)值包裝類和Character

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(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ǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論