《Java程序設(shè)計(jì)教程》06 繼承、多態(tài)與接口_第1頁(yè)
《Java程序設(shè)計(jì)教程》06 繼承、多態(tài)與接口_第2頁(yè)
《Java程序設(shè)計(jì)教程》06 繼承、多態(tài)與接口_第3頁(yè)
《Java程序設(shè)計(jì)教程》06 繼承、多態(tài)與接口_第4頁(yè)
《Java程序設(shè)計(jì)教程》06 繼承、多態(tài)與接口_第5頁(yè)
已閱讀5頁(yè),還剩47頁(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)介

第6章繼承、多態(tài)與接口本章學(xué)習(xí)目標(biāo):理解繼承與多態(tài)的概念和實(shí)現(xiàn)機(jī)制利用繼承與多態(tài)設(shè)計(jì)復(fù)雜的類掌握抽象類和接口的實(shí)現(xiàn)6.1繼承和多態(tài)當(dāng)一個(gè)類擁有另一個(gè)類的數(shù)據(jù)和操作時(shí),就稱這兩個(gè)類之間具有繼承關(guān)系,被繼承的類稱為父類或超類,繼承的類稱為子類。例子車自行車電車汽車6.1.1子類、父類與繼承機(jī)制一個(gè)父類可以同時(shí)擁有多個(gè)子類,該父類實(shí)際上是所有子類的公共成員變量和公共方法的集合,而子類是父類的特殊化,可對(duì)公共成員變量和方法在功能、內(nèi)涵方面加以擴(kuò)展和延伸。面向?qū)ο蟮睦^承特性中,還有一個(gè)關(guān)于單繼承和多繼承的概念。單繼承是指任何類都只有一個(gè)父類。多繼承是指一個(gè)類可以有一個(gè)以上的父類,它靜態(tài)數(shù)據(jù)和操作從所有這些父類中繼承的。Java只支持單重繼承,但支持接口(interface),一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。利用接口可以得到多繼承的優(yōu)點(diǎn),又沒有多繼承混亂、復(fù)雜的問題。6.2.2Java的繼承:創(chuàng)建子類Java中的繼承是通過(guò)extends關(guān)鍵字來(lái)實(shí)現(xiàn)的。格式為:

class子類名extends父類名稱{

……

}在定義子類時(shí),用extends關(guān)鍵字指明新定義子類的父類,這樣,兩個(gè)類之間就建立了繼承關(guān)系。新定義的類稱為子類或派生類。如果子類和父類在同一個(gè)包中,它可以從父類那里繼承所有非private的成員變量和方法作為自己的成員。如果子類和父類不在同一個(gè)包中,它可以從父類那里繼承protected、public的的成員變量和方法作為自己的成員。【例6-2】應(yīng)用繼承性的實(shí)例。classStudent{ //自定義“學(xué)生”類

intstu_id; //定義屬性:學(xué)生學(xué)號(hào)

voidset_id(intid){ //定義方法:設(shè)置學(xué)號(hào)

stu_id=id; } voidshow_id(){ //定義方法:顯示學(xué)號(hào)

System.out.println("thestudentIDis:"+stu_id); }}classUniversityStudentextendsStudent{

//定義子類

intdep_number; //定義子類特有的屬性變量

voidset_dep(intdep_num){ //定義子類特有的方法

dep_number=dep_num; } voidshow_dep(){ System.out.println("thedep_numberis:"+dep_number); } publicstaticvoidmain(Stringargs[]){ UniversityStudentLee=newUniversityStudent(); Lee.set_id(2007070130);//繼承父類學(xué)生的屬性

Lee.set_dep(701);

//使用本類的屬性

Lee.show_id(); //繼承父類學(xué)生的方法

Lee.show_dep();

//使用本類的方法

}}

成員變量的隱藏和方法的覆蓋1.成員變量的繼承子類可以繼承父類的所有非私有成員變量。2.成員變量的隱藏子類重新定義一個(gè)從父類那里繼承來(lái)的成員變量,變量完全相同,稱為成員變量的隱藏。3.方法的覆蓋方法的覆蓋是指子類重定義從父類繼承來(lái)的一個(gè)同名方法,此時(shí)子類將清除父類方法的影響。注意:子類在重新定義父類已有的方法時(shí),應(yīng)保持與父類完全相同的方法頭聲明,即應(yīng)與父類有完全相同的方法名、相同的參數(shù)表和相同的返回類型。【例6-4】成員變量的隱藏和方法的覆蓋示例。

classSuperClass{ intx;

……

voidsetX(){

x=0;

}

……

}

classSubClassextendsSuperClass{

intx;//成員變量的隱藏

……

voidsetX(){//方法的覆蓋

x=5;

}

……

}

方法的覆蓋與成員變量的隱藏的區(qū)別為:子類隱藏父類的成員變量只是使之不可見,父類的同名成員變量在子類對(duì)象中仍然占有自己獨(dú)立的內(nèi)存空間;而子類方法對(duì)父類同名方法的覆蓋將清除父類方法占用的內(nèi)存,從而使父類方法在子類對(duì)象中不存在。方法的覆蓋與成員變量的隱藏的意義:將父類行為和狀態(tài)改為自身的行為和狀態(tài),對(duì)外仍保持統(tǒng)一的接口和名字,不失繼承性。super子類可以對(duì)父類的同名成員變量和方法,分別實(shí)行隱藏和覆蓋。但是,有時(shí)需要在子類中訪問父類的變量和方法,Java提供的super就可以實(shí)現(xiàn)這訪問。它的使用有以下三種情形:訪問被隱藏的父類成員變量,如:

super.VariableName調(diào)用父類中被覆蓋的方法,如:

super.MethodName調(diào)用父類中的構(gòu)造方法,如:

super([paramList])6.1.3多態(tài)性多態(tài)性是由封裝性和繼承性引出的面向?qū)ο蟪绦蛟O(shè)計(jì)的另一大特征:在面向過(guò)程的程序設(shè)計(jì)中,各個(gè)方法(函數(shù))是不能重名的,否則就會(huì)編譯通不過(guò)。而在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,有時(shí)卻需要利用這樣的“重名”現(xiàn)象來(lái)提高程序的靈活度和簡(jiǎn)潔性。多態(tài)性是指同名的不同方法在程序中共存。即為同一個(gè)方法定義幾個(gè)版本,運(yùn)行時(shí)根據(jù)不同情況執(zhí)行不同的版本。調(diào)用者只需使用同一個(gè)方法名,系統(tǒng)會(huì)根據(jù)不同情況,調(diào)用相應(yīng)的不同方法,從而實(shí)現(xiàn)不同的功能。在Java語(yǔ)言中,多態(tài)性的實(shí)現(xiàn)有兩種方式:1、覆蓋(override)實(shí)現(xiàn)多態(tài)性2、重載(overload)實(shí)現(xiàn)多態(tài)性1、覆蓋實(shí)現(xiàn)動(dòng)態(tài)多態(tài)性覆蓋實(shí)現(xiàn)多態(tài)性通過(guò)子類對(duì)繼承父類方法的重定義來(lái)實(shí)現(xiàn)。使用時(shí)注意:在子類重定義父類方法時(shí),要求與父類原型(參數(shù)個(gè)數(shù)、類型、順序)完全相同。重寫方法的調(diào)用規(guī)則對(duì)于重寫的方法,Java運(yùn)行時(shí)系統(tǒng)根據(jù)調(diào)用該方法的實(shí)例的類型來(lái)決定選擇哪個(gè)方法調(diào)用。對(duì)于類的一個(gè)實(shí)例,如果子類重寫了父類的方法,則運(yùn)行時(shí)系統(tǒng)調(diào)用子類的方法。如果子類繼承了父類的方法(未重),則運(yùn)行時(shí)系統(tǒng)調(diào)用父類的方法。因此,一個(gè)對(duì)象可以通過(guò)引用子類的實(shí)例來(lái)調(diào)用于類的方法。【例6-5】重寫方法的調(diào)用規(guī)則示例。classA{

voidcallme(){

System.out.println("InsideA'scallme()method");

}}

classBextendsA{

voidcallme(){

System.out.println("InsideB'scallme()method");

}}

publicclassDispatch{

publicstaticvoidmain(Stringargs[]){

Aa=newB();a.callme();

}}運(yùn)行結(jié)果為:

InsideB'scallme()method

向上轉(zhuǎn)型

格式:父類名稱對(duì)象名=new子類名稱();

含義:右側(cè)創(chuàng)建一個(gè)子類對(duì)象,把它當(dāng)作父類來(lái)使用。注意:向上轉(zhuǎn)型一定是安全的。缺點(diǎn):一旦向上轉(zhuǎn)型,子類中原本特有的方法就不能再被調(diào)用了。方法重寫的兩個(gè)原則:改寫后的方法不能比被重寫的方法有更嚴(yán)格的訪問權(quán)限。改寫后的方法不能比被重寫的方法產(chǎn)生更多的例外。2、重載實(shí)現(xiàn)靜態(tài)多態(tài)性重載實(shí)現(xiàn)多態(tài)性是通過(guò)定義類中的多個(gè)同名的不同方法來(lái)實(shí)現(xiàn)的。編譯時(shí)則根據(jù)參數(shù)(個(gè)數(shù)、類型、順序)的不同來(lái)區(qū)分不同的方法。通過(guò)重載可定義多種同類的操作方法,調(diào)用時(shí)根據(jù)不同需要選擇不同的操作。與方法的覆蓋不同,重載不是子類對(duì)父類同名方法的重新定義,而是類對(duì)自身已有的同名方法的重新定義。由于重載發(fā)生在一個(gè)類里,不能用類名來(lái)區(qū)分不同的方法,所以采用不同的形式參數(shù)列表,包括形式參數(shù)的個(gè)數(shù)、類型、順序的不同,來(lái)區(qū)分重載的方法。importjava.awt.Point;classMyRect{intx1=0; inty1=0;intx2=0; inty2=0;MyRectbuildRect(intx1,inty1,intx2,inty2){//參數(shù)列表是四個(gè)坐標(biāo)值this.x1=x1; this.y1=y1;this.x2=x2; this.y2=y2;returnthis;}MyRectbuildRect(PointtopLeft,PointbottomRight){//參數(shù)列表是兩個(gè)Point類型的對(duì)象實(shí)例x1=topLeft.x; y1=topLeft.y;x2=bottomRight.x; y2=bottomRight.y;returnthis;}MyRectbuildRect(PointtopLeft,intw,inth){//參數(shù)列表是一個(gè)Point類型實(shí)例對(duì)象和寬w、高h(yuǎn)x1=topLeft.x; y1=topLeft.y;x2=(x1+w); y2=(y1+h);returnthis;}voidprintRect(){System.out.println("MyRect:<"+x1+","+y1);System.out.println(","+x2+","+y2+">");}}【例6-7】重載實(shí)現(xiàn)多態(tài)性舉例。該類中定義了矩形,用四個(gè)實(shí)例變量來(lái)定義這個(gè)矩形的左上角和右下角的坐標(biāo),x1、y1、x2、y2。另外定義了三個(gè)同名的不同buildRect()方法為這些實(shí)例變量設(shè)置值。publicclasscase6_7{publicstaticvoidmain(Stringargs[]){MyRectrect=newMyRect();rect.buildRect(25,25,50,50);rect.printRect();System.out.println("******");rect.buildRect(newPoint(10,10),newPoint(20,20));rect.printRect();System.out.println("******");rect.buildRect(newPoint(10,10),50,50);rect.printRect();System.out.println("******");}}6.2抽象類與接口6.2.1抽象類抽象類:用abstract關(guān)鍵字來(lái)修飾的類。聲明為abstract的類不能被實(shí)例化,它只提供一個(gè)類的抽象定義。要想實(shí)例化,該類只能作為父類,由子類來(lái)繼承,并在子類中實(shí)現(xiàn)抽象類中的所有抽象方法,讓子類成為具體的、有意義的類。抽象方法用abstract修飾,abstract類必須被繼承,abstract方法必須被重寫。

抽象方法:用abstract來(lái)修飾一個(gè)方法時(shí),該方法叫做抽象方法。抽象方法必須被重寫抽象方法只有聲明,不能有實(shí)現(xiàn)定義了抽象方法的類必須是抽象類【例6-9】抽象類舉例。abstractclassA{

abstractvoidcallme();

voidmetoo(){

System.out.println("InsideA'smetoo()method");

}

}

classBextendsA{

voidcallme(){

System.out.println("InsideB'scallme()method");

}

}

publicclassAbstract{

publicstaticvoidmain(Stringargs[]){

Ac=newB();

c.callme();

c.metoo();

}

}6.2.2接口接口(interface)就是方法定義和常量值的集合。從本質(zhì)上講,接口是一種特殊的抽象類,這種抽象類中只包含常量和方法的定義,而沒有方法的實(shí)現(xiàn)。

通過(guò)接口可以實(shí)現(xiàn)不相關(guān)類的相同行為,而不需要考慮這些類之間的層次關(guān)系。

通過(guò)接口可以指明多個(gè)類需要實(shí)現(xiàn)的方法。

通過(guò)接口可以了解對(duì)象的交互界面,而不需了解對(duì)象所對(duì)應(yīng)的類。接口是用來(lái)實(shí)現(xiàn)類間多重繼承功能的結(jié)構(gòu)在Java中,出于簡(jiǎn)化程序結(jié)構(gòu)的考慮,不支持類間的多重繼承而只支持單重繼承,即一個(gè)類至多只能有一個(gè)直接父類。接口的實(shí)現(xiàn)功能比多重繼承更強(qiáng)接口把方法的定義和類的層次區(qū)分開來(lái),通過(guò)它可以在運(yùn)行時(shí)動(dòng)態(tài)地定位所調(diào)用的方法;同時(shí),也可以實(shí)現(xiàn)“多重繼承”,且一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。正是這些機(jī)制使得接口提供了比多重繼承更簡(jiǎn)單,更靈活,而且更強(qiáng)健的功能。1.接口的定義[public]interface接口名[extends接口列表] { …… //常量定義和方法定義

}public指明任意類均可以使用這個(gè)接口。在缺省情況下,只有與該接口定義在同一個(gè)包中的類才可以訪問這個(gè)接口。extends子句與類聲明中的extends子句基本相同,不同的是一個(gè)接口可以有多個(gè)父接口,用逗號(hào)隔開,而一個(gè)類只能有一個(gè)父類。子接口繼承父接口中所有常量和方法。接口體中包括常量定義和方法定義,其格式如下:

typeconstantName=Value; returnTypemethodName([paramList]);

在接口中定義的常量可以被用來(lái)實(shí)現(xiàn)該接口的多個(gè)類共享,與C語(yǔ)言中的const定義常量是相似的。在接口中定義的常量具有public、final、static的屬性。接口中只進(jìn)行方法的聲明,而不提供方法的實(shí)現(xiàn),所以,方法定義沒有方法體,且用分號(hào)(;)結(jié)尾。在接口中聲明的方法具有public和abstract屬性。另外,如果在子接口中定義了和父接口同名的常量或相同的方法,則父接口中的常量被隱藏,方法被覆蓋。例:

interfaceCollection { intMAX_NUM=100; voidadd(ObjectobjAdd); voiddelete(ObjectobjDelet); Objectfind(ObjectobjFind); intcurrentCount(); }接口定義中聲明了一個(gè)常量和四個(gè)方法。這個(gè)接口可以由隊(duì)列、堆棧、鏈表等來(lái)實(shí)現(xiàn)。2.接口的實(shí)現(xiàn)接口的聲明僅僅給出了抽象方法,要具體地實(shí)現(xiàn)接口所規(guī)定的功能,則需某個(gè)類為接口中的抽象方法定義實(shí)在的方法體,這就稱為接口的實(shí)現(xiàn)。在類的聲明中,用implements句子表示一個(gè)類將要實(shí)現(xiàn)某個(gè)接口,在類體中可以引用接口中定義的常量,而且必須實(shí)現(xiàn)接口中定義的所有方法。一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,在implements子句中用逗號(hào)分隔。【例6-11】接口的實(shí)現(xiàn):在類FIFOQueue中實(shí)現(xiàn)上面所定義的接口collection。

classFIFOQueueimplementscollection{

voidadd(Objectobj){

...

}

voiddelete(Objectobj){

...

}

Objectfind(Objectobj){

...

}

intcurrentCount{

...

}

}

注意:在類中實(shí)現(xiàn)接口所定義的方法時(shí),方法的聲明必須與接口中所定義的完全一致。在類中實(shí)現(xiàn)接口所定義的方法時(shí),必須顯式地使用public修飾符,否則將被系統(tǒng)警告為縮小了接口中定義的方法的訪問控制范圍。抽象類可以不實(shí)現(xiàn)接口的抽象方法,而非抽象類必須實(shí)現(xiàn)接口中的所有方法。6.3其他6.3.1final關(guān)鍵字final類表示該類是最終類,不能再被繼承。由于安全性的原因或者是面向?qū)ο蟮脑O(shè)計(jì)上的考慮,有時(shí)候希望一些類不能被繼承,例如,Java中的String類,它對(duì)編譯器和解釋器的正常運(yùn)行有很重要的作用,不能輕易改變它,因此把它修飾為final類,使它不能被繼承,這就保證了String類型的唯一性。final修飾方法表示該方法是最終方法,用final修飾的方法不能再被子類重寫。final修飾變量如果一個(gè)變量前面有final修飾符,那么這個(gè)變量就變成了常量。一旦被賦值,就不允許在程序的其他地方修改其值。6.3.2實(shí)例成員和類成員Java類包括兩種類型的成員:實(shí)例成員和類成員。除非static修飾,定義在類中的成員都是實(shí)例成員。【例】實(shí)例成員舉例classAnIntergerNamedX{ intx; //實(shí)例變量 publicintx(){ //實(shí)例方法 returnx; } publicvoidsetX(intnewX){//實(shí)例方法 x=newX; }}聲明了實(shí)例變量之后,當(dāng)每次創(chuàng)建類的一個(gè)新對(duì)象時(shí),系統(tǒng)就會(huì)為該對(duì)象的所有成員創(chuàng)建實(shí)例變量的副本,然后就可以通過(guò)對(duì)象訪問這些實(shí)例變量。實(shí)例方法是對(duì)當(dāng)前對(duì)象實(shí)例變量進(jìn)行操作的,而且可以訪問類變量。static在變量或方法之前,表明它們是屬于類的,稱為類方法(靜態(tài)方法)或類變量(靜態(tài)變量)。類成員用static修飾符聲明,格式如下:

statictypeclassVar;

staticreturnTypeclassMethod([paramlist]){

……

}分別聲明了類變量和類方法。類變量類變量用static修飾符聲明。系統(tǒng)只為每個(gè)類分配類變量,而不管類創(chuàng)建的對(duì)象有多少。當(dāng)?shù)谝淮握{(diào)用類的時(shí)候,系統(tǒng)為該類變量分配內(nèi)存,所有的對(duì)象共享了該類的類變量。因此,可以通過(guò)類本身或者某個(gè)對(duì)象來(lái)訪問該類變量?!纠款愖兞颗e例classAnIntergerNamedX{ staticintx; publicintx(){ returnx; } publicvoidsetX(intnewX){ x=newX; }}輸出的兩個(gè)變量結(jié)果相同,這是因?yàn)閤是一個(gè)類變量,因此,就只有該類變量的唯一副本,它被該類的所有對(duì)象所共享,包括myX和anotherX。當(dāng)在任一對(duì)象中調(diào)用setX的時(shí)候,也就改變了該類所有對(duì)象所共享的值。

結(jié)果輸出為:myX.x=2anotherX.x=2類方法為了指定方法為一個(gè)類方法,可以在方法聲明的地方使用static關(guān)鍵字。類方法只能操作類變量而不能直接訪問在類中定義的實(shí)例變量,除非這些類方法創(chuàng)建了一個(gè)新的對(duì)象,并通過(guò)對(duì)象訪問它們。類方法可以在類中被調(diào)用,不必通過(guò)一個(gè)實(shí)例來(lái)調(diào)用一個(gè)類方法。Java程序的入口方法main()就是一個(gè)類方法?!纠坎徽_的引用classAnIntergerNamedX{ intx; staticpublicintx(){ returnx; } staticpublicvoidsetX(intnewX){ x=newX; }}

當(dāng)編譯這個(gè)類時(shí),就會(huì)出錯(cuò)。原因是類方法不能訪問實(shí)例變量。

static解決方法:1.將變量變成類變量(使用static修飾符);

2.創(chuàng)建一個(gè)類的對(duì)象,并且通過(guò)該對(duì)象來(lái)訪問變量。

注意:同一個(gè)類的實(shí)例方法可以訪問該類的類變量和類方法;

而類方法只能訪問該類的類變量和類方法,不能直接訪問實(shí)例的變量和方法。6.3.3類java.lang.Object類java.lang.Object處于Java開發(fā)環(huán)境的類層次樹的根部,其他所有類都是它的直接或間接子類(派生類)。Object類定義了一些所有對(duì)象都具有的最基本的屬性和行為,默認(rèn)方法如下:1.equals()

比較兩個(gè)對(duì)象是否相同,如果相同,則返回true,否則返回false。2.getClass()

返回一個(gè)對(duì)象在運(yùn)行時(shí)所對(duì)應(yīng)的類的表示class*。3.toString()

重寫toString()方法可以適當(dāng)?shù)仫@示對(duì)象的屬性信息等,以便于程序調(diào)試。4.finalize()

該方法用于釋放對(duì)象,但要到垃圾收集時(shí)才進(jìn)行。5.notify()、notifyAll()和wait()

這些方法用于多線程處理中的線程同步。多線程技術(shù)將在后面第8章中介紹。6.3.4內(nèi)部類在《Thinkinginjava》中

溫馨提示

  • 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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 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)論