版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
繼承是指從一個(gè)父類(父類)派生出派生類(子類)的過程;繼承使用關(guān)鍵字extends;對于類成員,可以使用public、protected、缺省和private這4種訪問權(quán)限修飾符;對于類,可以使用public和缺省這2個(gè)訪問權(quán)限;創(chuàng)建子類實(shí)例時(shí),必須先執(zhí)行父類的構(gòu)造方法,然后再執(zhí)行子類的構(gòu)造方法;super關(guān)鍵字有兩種主要用途,都與父類有關(guān)。回顧現(xiàn)在是1頁\一共有64頁\編輯于星期一為什么使用多態(tài)?寵物生病了,需要主人給寵物看病不同寵物看病過程不一樣不同寵物恢復(fù)后體力值不一樣
打針
吃藥
吃藥
療養(yǎng)
狗狗
Q仔
現(xiàn)在是2頁\一共有64頁\編輯于星期一為什么使用多態(tài)?編碼實(shí)現(xiàn)publicclassMaster{publicvoidCure(Dogdog){if(dog.getHealth()<50){dog.setHealth(60);System.out.println("打針、吃藥");}}publicvoidCure(Penguinpenguin){if(penguin.getHealth()<50)penguin.setHealth(70);System.out.println("吃藥、療養(yǎng)");}}
主人類……Mastermaster=newMaster();master.Cure(dog);master.Cure(penguin);……
測試方法現(xiàn)在是3頁\一共有64頁\編輯于星期一為什么使用多態(tài)?如果又需要給XXX看病,怎么辦?添加XXX類,繼承Pet類修改Master類,添加給XXX看病的方法使用多態(tài)優(yōu)化設(shè)計(jì)頻繁修改代碼,代碼可擴(kuò)展性、可維護(hù)性差現(xiàn)在是4頁\一共有64頁\編輯于星期一為什么使用多態(tài)?使用多態(tài)優(yōu)化后的代碼……Petpet=newDog();Mastermaster=newMaster();master.Cure(pet);……
測試方法publicclassDogextendsPet{publicvoidtoHospital(){this.setHealth(60);System.out.println("打針、吃藥");}}publicclassPenguinextendsPet{publicvoidtoHospital(){
this.setHealth(70);System.out.println("吃藥、療養(yǎng)");}}publicclassMaster{publicvoidCure(Petpet){if(pet.getHealth()<50)pet.toHospital();}}
主人類Dog類Penguin類1234又要給XXX看病時(shí),只需:1.編寫XXX類繼承Pet類(舊方案也需要)2.創(chuàng)建XXX類對象(舊方案也需要)3.其他代碼不變(不用修改Master類)現(xiàn)在是5頁\一共有64頁\編輯于星期一什么是多態(tài)?生活中的多態(tài)你能列舉出一個(gè)多態(tài)的生活示例嗎?程序中的多態(tài)同一個(gè)引用類型,使用不同的實(shí)例而執(zhí)行不同操作父類引用,子類對象同一種事物,由于條件不同,產(chǎn)生的結(jié)果也不同現(xiàn)在是6頁\一共有64頁\編輯于星期一多態(tài)性(polymorphism)概念:是面向?qū)ο蟪绦蛟O(shè)計(jì)的另一個(gè)重要特征,其基本含義是“擁有多種形態(tài)”,具體指在程序中用相同的名稱來表示不同的含義。例如:用同一方法名來表示不同的操作。類型:有兩種靜態(tài)多態(tài)性:包括變量的隱藏、方法的重載動(dòng)態(tài)多態(tài)性:在編譯時(shí)不能確定調(diào)用方法,只有在運(yùn)行時(shí)才能確定調(diào)用方法,又稱為運(yùn)行時(shí)的多態(tài)性。7現(xiàn)在是7頁\一共有64頁\編輯于星期一靜態(tài)多態(tài)靜態(tài)多態(tài)也稱為編譯時(shí)多態(tài),即在編譯時(shí)決定調(diào)用哪個(gè)方法;靜態(tài)多態(tài)一般是指方法重載;只要構(gòu)成了方法重載,就可以認(rèn)為形成了靜態(tài)多態(tài)的條件;靜態(tài)多態(tài)與是否發(fā)生繼承沒有必然聯(lián)系?,F(xiàn)在是8頁\一共有64頁\編輯于星期一動(dòng)態(tài)多態(tài)動(dòng)態(tài)多態(tài)也稱為運(yùn)行時(shí)多態(tài),即在運(yùn)行時(shí)才能確定調(diào)用哪個(gè)方法;形成動(dòng)態(tài)多態(tài)必須具體以下條件:必須要有繼承的情況存在;在繼承中必須要有方法覆蓋;必須由父類的引用指向派生類的實(shí)例,并且通過父類的引用調(diào)用被覆蓋的方法;由上述條件可以看出,繼承是實(shí)現(xiàn)動(dòng)態(tài)多態(tài)的首要前提?,F(xiàn)在是9頁\一共有64頁\編輯于星期一下面主要介紹動(dòng)態(tài)多態(tài)性//多態(tài)性的例子classAnimal{
publicvoidroar(){ System.out.println("動(dòng)物:..."); }}classCatextendsAnimal{
publicvoidroar(){ System.out.println("貓:喵,喵,喵,..."); }}classDogextendsAnimal{
publicvoidroar(){ System.out.println("狗:汪,汪,汪,..."); }}10現(xiàn)在是10頁\一共有64頁\編輯于星期一//多態(tài)性的例子(續(xù))publicclassAnimalTest{ publicstaticvoidmain(Stringargs[]){ Animalam=newAnimal();
am.roar(); am=newDog();
am.roar(); am=newCat();
am.roar(); }}程序運(yùn)行結(jié)果:動(dòng)物:...狗:汪,汪,汪,...貓:喵,喵,喵,... 根據(jù)對象的賦值規(guī)則,可以把子類對象賦給父類對象名,這是允許。當(dāng)用同一形式:
父類對象名.roar()
去調(diào)用時(shí),能夠根據(jù)子類對象的不同,得到不同的結(jié)果,這就是多態(tài)性。11現(xiàn)在是11頁\一共有64頁\編輯于星期一實(shí)現(xiàn)多態(tài)的流程用多態(tài)實(shí)現(xiàn)打印機(jī)分為黑白打印機(jī)和彩色打印機(jī)不同類型的打印機(jī)打印效果不同黑白打印機(jī)彩色打印機(jī)打印現(xiàn)在是12頁\一共有64頁\編輯于星期一實(shí)現(xiàn)多態(tài)的設(shè)計(jì)思路使用多態(tài)實(shí)現(xiàn)思路編寫父類編寫子類,子類重寫(覆蓋)父類方法運(yùn)行時(shí),使用父類的類型,子類的對象計(jì)算機(jī)可以連接各種打印機(jī)無論連接何種打印機(jī)打印方法都相同根據(jù)連接打印機(jī)不同,效果也不同現(xiàn)在是13頁\一共有64頁\編輯于星期一實(shí)現(xiàn)多態(tài)
編碼實(shí)現(xiàn)實(shí)現(xiàn)多態(tài)的兩個(gè)要素:1.方法重寫2.使用父類類型classPrinter{
print(Stringstr);}classColorPrinterextendsPrinter{
print(Stringstr)
{System.out.println("輸出彩色的"+str);}}classBlackPrinterextendsPrinter{
print(Stringstr)
{System.out.println("輸出黑白的"+str);}}publicstaticvoidmain(String[]args){
Printerp=newColorPrinter();p.print();p=newBlackPrinter();p.print();}父類子類運(yùn)行同一種操作方式,不同的操作對象只能調(diào)用父類已經(jīng)定義的方法繼承是子類使用父類的方法,而多態(tài)則是父類使用子類的方法。(把父類當(dāng)做子類來用)現(xiàn)在是14頁\一共有64頁\編輯于星期一方法重寫(覆蓋)方法重寫的規(guī)則在繼承關(guān)系的子類中重寫的方法名、參數(shù)、返回值類型必須與父類相同私有方法不能繼承因而也無法重寫
位置方法名參數(shù)表返回值訪問修飾符方法重寫子類相同相同相同不能比父類更嚴(yán)格方法重載同類相同不相同無關(guān)無關(guān)方法重寫override方法重載overload
VS現(xiàn)在是15頁\一共有64頁\編輯于星期一實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)技術(shù)的條件:有一個(gè)繼承層次關(guān)系;在子類中重寫父類的方法;通過父類的引用對子類對象進(jìn)行調(diào)用。采用多態(tài)技術(shù)的優(yōu)點(diǎn): 引進(jìn)多態(tài)技術(shù)之后,盡管子類的對象千差萬別,但都可以采用父類引用.方法名([參數(shù)])統(tǒng)一方式來調(diào)用,在程序運(yùn)行時(shí)能根據(jù)子對象的不同得到不同的結(jié)果。這種“以不變應(yīng)萬變”的形式可以規(guī)范、簡化程序設(shè)計(jì),符合軟件工程的“一個(gè)接口,多種方法”思想。
16現(xiàn)在是16頁\一共有64頁\編輯于星期一多態(tài)的運(yùn)行機(jī)制多態(tài)的運(yùn)行機(jī)制
Java多態(tài)機(jī)制是基于“方法綁定(binding)”,就是建立methodcall(方法調(diào)用)和methodbody(方法本體)的關(guān)聯(lián)。如果綁定動(dòng)作發(fā)生于程序執(zhí)行前(由編譯器和連接器完成),稱為“先期綁定”。對于面向過程的語言它們沒有其他選擇,一定是先期綁定。比如C編譯器只有一種methodcall,就是先期綁定。(C++有先期聯(lián)編和后期聯(lián)編)
當(dāng)有多態(tài)的情況時(shí),解決方案便是所謂的后期綁定(latebinding):綁定動(dòng)作將在執(zhí)行期才根據(jù)對象型別而進(jìn)行。后期綁定也被稱為執(zhí)行期綁定(run-timebinding)或動(dòng)態(tài)綁定(dynamicbinding)。Java的所有方法,除了被聲明為final者,都使用后期綁定。將方法聲明為final型可以有效防止他人覆寫該函數(shù)。但是或許更重要的是,這么做可以“關(guān)閉”動(dòng)態(tài)綁定?;蛘哒f,這么做便是告訴編譯器:動(dòng)態(tài)綁定是不需要的。于是編譯器可以產(chǎn)生效率較佳的程序代碼?,F(xiàn)在是17頁\一共有64頁\編輯于星期一引用轉(zhuǎn)型父類的引用可以指向子類的對象,如:
BaseClassobj=newDerivedClass();
這樣的語句是合法的;但是子類的引用則不可以指向父類的對象,如:
DerivedClassobj=newBaseClass();
這樣的語句將引發(fā)錯(cuò)誤?,F(xiàn)在是18頁\一共有64頁\編輯于星期一引用轉(zhuǎn)型示例classPerson{//定義人類
……}classStudentextendsPerson{//學(xué)生類繼承于人類
……}public
classOverriddenDemo{
public
static
voidmain(String[]args){
//正確,所有的學(xué)生一定是人
Personper=newStudent();
//錯(cuò)誤,并不是所有的人都是學(xué)生
Studentstd=newPerson();}}現(xiàn)在是19頁\一共有64頁\編輯于星期一多態(tài)性實(shí)例分析Example例如動(dòng)物園的飼養(yǎng)員能夠給各種各樣的動(dòng)物喂食。
圖1顯示了飼養(yǎng)員Feeder、食物Food和動(dòng)物Animal以及它的子類的類框圖?,F(xiàn)在是20頁\一共有64頁\編輯于星期一多態(tài)性實(shí)例分析
圖1飼養(yǎng)員Feeder、食物Food和動(dòng)物Animal以及它的子類的類框圖現(xiàn)在是21頁\一共有64頁\編輯于星期一多態(tài)性實(shí)例分析可以把Feeder、Animal和Food都看成獨(dú)立的子系統(tǒng)。Feeder類的定義如下:
publicclassFeeder{
publicvoidfeed(Animalanimal,Foodfood){
animal.eat(food);
}
}以下程序演示一個(gè)飼養(yǎng)員分別給一只狗喂肉骨頭,給一只貓喂魚。
Feederfeeder=newFeeder();
Animalanimal=newDog();
Foodfood=newBone();
feeder.feed(animal,food);
animal=newCat();
food=newFish();
feeder.feed(animal,food);
//給狗喂肉骨頭//給貓喂魚現(xiàn)在是22頁\一共有64頁\編輯于星期一多態(tài)性實(shí)例分析Java語言允許某個(gè)類型的引用變量引用子類的實(shí)例,而且可以對這個(gè)引用變量進(jìn)行類型轉(zhuǎn)換:Animalanimal=newDog();
Dogdog=(Dog)animal;
Creaturecreature=animal;
如圖2所示,如果把引用變量轉(zhuǎn)換為子類類型,稱為向下轉(zhuǎn)型,如果把引用變量轉(zhuǎn)換為父類類型,稱為向上轉(zhuǎn)型。在進(jìn)行引用變量的類型轉(zhuǎn)換時(shí),會受到各種限制。而且在通過引用變量訪問它所引用的實(shí)例的靜態(tài)屬性、靜態(tài)方法、實(shí)例屬性、實(shí)例方法,以及從父類中繼承的方法和屬性時(shí),Java虛擬機(jī)會采用不同的綁定機(jī)制。
//向下轉(zhuǎn)型,把Animal類型轉(zhuǎn)換為Dog類型
//向上轉(zhuǎn)型,把Animal類型轉(zhuǎn)換為
Creature類型現(xiàn)在是23頁\一共有64頁\編輯于星期一多態(tài)
圖2類型轉(zhuǎn)換現(xiàn)在是24頁\一共有64頁\編輯于星期一多態(tài)性實(shí)例分析下面通過具體的例子來演示多態(tài)的各種特性。在下面的例程中,Base父類和Sub子類中都定義了實(shí)例變量var、實(shí)例方法method()、靜態(tài)變量staticVar和靜態(tài)方法staticMethod(),此外,在Sub類中還定義了實(shí)例變量subVar和subMethod()。Sub.java
packagepoly;
classBase{
Stringvar="BaseVar";
staticStringstaticVar="StaticBaseVar";
voidmethod(){
System.out.println("Basemethod");
}
staticvoidstaticMethod(){System.out.println("StaticBasemethod");
}
}//成員(實(shí)例)變量//靜態(tài)變量//成員(實(shí)例)方法//靜態(tài)方法
現(xiàn)在是25頁\一共有64頁\編輯于星期一publicclassSubextendsBase{
Stringvar=“SubVar”;
//成員(實(shí)例)變量
staticStringstaticVar="StaticSubVar";
//靜態(tài)變量voidmethod(){
//覆蓋父類的method()方法
System.out.println("Submethod");
}
staticvoidstaticMethod(){
//隱藏父類的staticMethod()方法
System.out.println("StaticSubmethod");
}StringsubVar="VaronlybelongingtoSub";
voidsubMethod(){
System.out.println("MethodonlybelongingtoSub");
}
publicstaticvoidmain(Stringargs[]){
Basewho=newSub();
//who被聲明為Base類型,引用Sub實(shí)例
System.out.println("who.var="+who.var);
System.out.println("who.staticVar="+who.staticVar);
who.method();
who.staticMethod();
}
}//打印Base類的var變量//打印Base類的staticVar變量//打印Sub實(shí)例的method()方法//打印Base類的staticMethod()方法現(xiàn)在是26頁\一共有64頁\編輯于星期一多態(tài)的一些細(xì)節(jié)(1)對于一個(gè)引用類型的變量,Java編譯器按照它聲明的類型來處理。例如在以下代碼中,編譯器認(rèn)為who是Base類型的引用變量,不存在subVar成員變量和subMethod()方法,所以編譯出錯(cuò):Basewho=newSub();
//who是Base類型
who.subVar=“123”;
//編譯出錯(cuò),提示在Base類中沒有subVar屬性
who.subMethod();
//編譯出錯(cuò),提示在Base類中沒有subMethod()方法如果要訪問Sub類的成員,必須通過強(qiáng)制類型的轉(zhuǎn)換:
Basewho=newSub();
//who是Base類型
((Sub)who).subVar="123";
//編譯成功,把Base引用類型強(qiáng)制轉(zhuǎn)換為Sub引用類型
((Sub)who).subMethod();
//編譯成功,把Base引用類型強(qiáng)制轉(zhuǎn)換為Sub引用類型現(xiàn)在是27頁\一共有64頁\編輯于星期一多態(tài)的一些細(xì)節(jié)Java編譯器允許具有直接或間接繼承關(guān)系的類之間進(jìn)行類型轉(zhuǎn)換.對于向上轉(zhuǎn)型,不必使用強(qiáng)制類型轉(zhuǎn)換,因?yàn)樽宇惖膶ο罂隙ㄒ部煽醋鞲割惖膶ο蟆@缫粋€(gè)Dog對象是一個(gè)Animal對象,也是一個(gè)Creature對象,也是一個(gè)Object對象:Dogdog=newDog();
Creaturecreature=dog;
//編譯成功,把Dog引用類型直接轉(zhuǎn)換為Creature引用類型
Objectobject=dog;
//編譯成功,把Dog引用類型直接轉(zhuǎn)換為Object引用類型對于向下轉(zhuǎn)型,必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換:Creaturecreature=newCat();
Animalanimal=(Animal)creature;
//編譯成功,把Creature引用類型強(qiáng)制轉(zhuǎn)換為Animal引用類型
Catcat=(Cat)creature;
//編譯成功,把Creature引用類型強(qiáng)制轉(zhuǎn)換為Cat引用類型
Dogdog=(Dog)creature;
//編譯成功,把Creature引用類型強(qiáng)制轉(zhuǎn)換為Dog引用類型現(xiàn)在是28頁\一共有64頁\編輯于星期一多態(tài)的一些細(xì)節(jié)假如兩種類型之間沒有繼承關(guān)系,即不在繼承樹的同一個(gè)繼承分支上,那么Java編譯器不允許進(jìn)行類型轉(zhuǎn)換,例如:
Dogdog=newDog();
Catcat=(Cat)dog;
//編譯出錯(cuò),不允許把Dog引用類型轉(zhuǎn)換為Cat引用類型(2)對于一個(gè)引用類型變量,運(yùn)行時(shí)Java虛擬機(jī)按照它實(shí)際引用的對象來處理。例如以下代碼雖然編譯可以通過,但運(yùn)行時(shí)會拋出ClassCastException運(yùn)行時(shí)異常:Basewho=newBase();
//who引用Base類的實(shí)例
Subs=(Sub)who;
//運(yùn)行時(shí)拋出ClassCastException
在運(yùn)行時(shí),子類的對象可以轉(zhuǎn)換為父類類型,而父類的對象實(shí)際上無法轉(zhuǎn)換為子類類型。因?yàn)橥ㄋ椎闹v,父類擁有的成員子類肯定也有,而子類擁有的成員父類不一定有?,F(xiàn)在是29頁\一共有64頁\編輯于星期一多態(tài)的一些細(xì)節(jié)假定Java虛擬機(jī)能夠把子類對象轉(zhuǎn)換為父類類型,那么以下代碼中的sub.subMethod()方法無法執(zhí)行:
Basewho=newBase();
//who引用Base類的實(shí)例
Subsub=(Sub)who;
//假定運(yùn)行時(shí)未出錯(cuò)
sub.subMethod();
//sub引用變量實(shí)際上引用Base實(shí)例,而Base實(shí)例沒有subMethod()方法
由此可見,在運(yùn)行時(shí),Java虛擬機(jī)無法把子類對象轉(zhuǎn)變?yōu)楦割愵愋汀R韵麓a盡管能夠編譯成功,但在運(yùn)行時(shí),creature變量引用的Cat對象無法轉(zhuǎn)變?yōu)镈og類型,因此會拋出ClassCastException:
Creaturecreature=newCat();
Animalanimal=(Animal)creature;
//運(yùn)行正常,Cat對象可轉(zhuǎn)換為Animal類型
Catcat=(Cat)creature;
//運(yùn)行正常,Cat對象可以被Cat類型的引用變量引用
Dogdog=(Dog)creature;
//運(yùn)行時(shí)拋出ClassCastException,Cat對象不可轉(zhuǎn)換為Dog類型(但是會編譯成功)現(xiàn)在是30頁\一共有64頁\編輯于星期一(3)在運(yùn)行時(shí)環(huán)境中,通過引用類型變量來訪問所引用對象的方法和屬性時(shí),Java虛擬機(jī)采用以下綁定規(guī)則:
1)成員(實(shí)例)方法與引用變量實(shí)際引用的對象的方法綁定,這種綁定屬于動(dòng)態(tài)綁定,因?yàn)槭窃谶\(yùn)行時(shí)由Java虛擬機(jī)動(dòng)態(tài)決定的。
2)靜態(tài)方法與引用變量所聲明的類型的方法綁定,這種綁定屬于靜態(tài)綁定,因?yàn)閷?shí)際上是在編譯階段就已經(jīng)作了綁定。
3)成員變量(包括靜態(tài)變量和實(shí)例變量)與引用變量所聲明的類型的成員變量綁定,這種綁定屬于靜態(tài)綁定,因?yàn)閷?shí)際上是在編譯階段就已經(jīng)作了綁定。多態(tài)的一些細(xì)節(jié)現(xiàn)在是31頁\一共有64頁\編輯于星期一例如,對于以下這段代碼:
Basewho=newSub();
//who被聲明為Base類型,引用Sub實(shí)例對象
System.out.println("who.var="+who.var);
//打印Base類的var變量
System.out.println("who.staticVar="+who.staticVar);
//打印Base類的staticVar變量
who.method();
//打印Sub實(shí)例的method()方法
who.staticMethod();
//打印Base類的staticMethod()方法
運(yùn)行時(shí)將會輸出如下結(jié)果:
who.var=BaseVar
who.staticVar=StaticBaseVar
Submethod
StaticBasemethod多態(tài)的一些細(xì)節(jié)現(xiàn)在是32頁\一共有64頁\編輯于星期一再看一個(gè)例子:
publicabstractclassA{
abstractvoidmethod();
voidtest(){
method();
//到底調(diào)用哪個(gè)類的mehtod()方法?
}
}
publicclassBextendsA{
voidmethod(){
//覆蓋父類的method()方法
System.out.println("Sub");
}
publicstaticvoidmain(Stringargs[]){
newB().test();
}
}多態(tài)的一些細(xì)節(jié)現(xiàn)在是33頁\一共有64頁\編輯于星期一運(yùn)行類B的main()方法將打印"Sub"。方法test()在父類A中定義,它調(diào)用了方法method()。雖然方法method()在類A中被定義為是抽象的,它仍然可以被調(diào)用,因?yàn)樵谶\(yùn)行時(shí)環(huán)境中,Java虛擬機(jī)會執(zhí)行類B的實(shí)例的method()方法。一個(gè)實(shí)例所屬的類肯定實(shí)現(xiàn)了父類中所有的抽象方法(否則這個(gè)類不能被實(shí)例化)。再看一個(gè)例子:
publicclassA{
voidmethod(){System.out.println("Base");}
voidtest(){method();}
}
publicclassBextendsA{
voidmethod(){System.out.println("Sub");}publicstaticvoidmain(Stringargs[]){
newA().test();
//調(diào)用類A的method()方法
newB().test();
//調(diào)用類B的method()方法
}
多態(tài)的一些細(xì)節(jié)現(xiàn)在是34頁\一共有64頁\編輯于星期一運(yùn)行這段代碼將打?。?/p>
Base
Subtest()方法在父類A中定義,它調(diào)用了method()方法,和上面一個(gè)例子的區(qū)別是父類A的method()方法不是抽象的。但是通過newB().test()調(diào)用method()方法,執(zhí)行的仍然是子類B的method()方法。由此可以更深入地體會動(dòng)態(tài)綁定的思想:在運(yùn)行環(huán)境中,當(dāng)通過B類的實(shí)例去調(diào)用一系列的實(shí)例方法(包括一個(gè)方法調(diào)用的另一個(gè)方法),將優(yōu)先和B類本身包含的實(shí)例方法動(dòng)態(tài)綁定,如果B類沒有定義這個(gè)實(shí)例方法,才會和從父類A中繼承來的實(shí)例方法動(dòng)態(tài)綁定。多態(tài)的一些細(xì)節(jié)現(xiàn)在是35頁\一共有64頁\編輯于星期一instanceof運(yùn)算符:功能:用于判斷一個(gè)類是否實(shí)現(xiàn)接口,也可用來判斷一個(gè)對象是否屬于一個(gè)類。格式:對象instanceof類或接口結(jié)果:true或false//程序片斷Personp=newPerson();Students=newStudent();System.out.println("人:p");System.out.println("學(xué)生:s");System.out.println("sinstanceofStudent:"+(sinstanceofStudent));System.out.println("sinstanceofPerson:"+(sinstanceofPerson));System.out.println("pinstanceofPerson:"+(pinstanceofPerson)); System.out.println("pinstanceofStudent:"+(pinstanceofStudent));程序運(yùn)行結(jié)果:人:p學(xué)生:ssinstanceofStudent:truesinstanceofPerson:truepinstanceofPerson:truepinstanceofStudent:false36現(xiàn)在是36頁\一共有64頁\編輯于星期一instanceof運(yùn)算符在強(qiáng)制類型轉(zhuǎn)換之前通過instanceof運(yùn)算符檢查對象的真實(shí)類型,可以避免類型轉(zhuǎn)換異常,從而提高代碼健壯性對象instanceof
類或接口/***測試instanceof運(yùn)算符的使用。*/publicclassTestPoly2{publicstaticvoidmain(String[]args){Petpet=newPenguin(“Q仔”,“QQ企鵝");//Petpet=newDog(“旺財(cái)”,“土狗");pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}/***測試instanceof運(yùn)算符的使用。*/publicclassTestPoly2{publicstaticvoidmain(String[]args){//Petpet=newPenguin(“Q仔”,“QQ企鵝");Petpet=newDog(“旺財(cái)”,“土狗");pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}注釋創(chuàng)建Penguin對象語句,取消創(chuàng)建Dog對象語句的注釋現(xiàn)在是37頁\一共有64頁\編輯于星期一回顧繼承:繼承現(xiàn)在是38頁\一共有64頁\編輯于星期一導(dǎo)入:為什么使用抽象類?如果我們想訪問調(diào)用子類Dog的print()方法。以下代碼有什么問題?Java中也使用抽象類,限制實(shí)例化Petpet=newPet();pet.print();實(shí)例化Pet沒有意義publicabstractclassPet{
}
通過抽象類來改進(jìn)實(shí)現(xiàn)現(xiàn)在是39頁\一共有64頁\編輯于星期一導(dǎo)入:為什么使用抽象方法?如果父類的方法沒機(jī)會被訪問調(diào)用,以下代碼有什么問題?◎可以使用抽象方法來優(yōu)化抽象方法沒有方法體抽象方法必須在抽象類里抽象方法必須在子類中被實(shí)現(xiàn),除非子類是抽象類publicabstractvoidprint();沒有方法體publicabstractclassPet{
publicvoidprint(){//…}}每個(gè)子類的print()方法實(shí)現(xiàn)不同,父類print()方法的實(shí)現(xiàn)是多余的。現(xiàn)在是40頁\一共有64頁\編輯于星期一抽象類(abstract)引例
抽象是面向?qū)ο蟮囊环N重要方法,通過抽象我們能夠設(shè)計(jì)一個(gè)更普通、更通用的類,例:從許許多多學(xué)生中,抽象出Student類,再從學(xué)生、工人、農(nóng)民、…抽象出Person類。
下面,我們來分析一個(gè)例子:Shape類(周長、面積)Circle類(周長、面積)Rect類(周長、面積)
Shape類是假想出的共同父類,現(xiàn)實(shí)中不存在叫“形狀”的東西,若去實(shí)例化這樣的對象很勉強(qiáng)。為阻止生成Shape類對象,可以將該類聲明為抽象類。
41現(xiàn)在是41頁\一共有64頁\編輯于星期一抽象方法與抽象類
關(guān)鍵字abstract可用來修飾方法和類,表示“尚未實(shí)現(xiàn)”的含義:如果方法的聲明中使用了abstract修飾符,那么該方法就稱為抽象方法。這表示該類中不提供方法的實(shí)現(xiàn),即不定義方法體。格式:訪問權(quán)限abstract返回類型方法名([參數(shù)表]);//無方法體例如:將前面Shape類的兩個(gè)方法聲明為抽象方法:
publicabstractdoublegetArea();
publicabstractdoublegetPerimeter();注意:◎無方法體與方法體為空是兩個(gè)不同的概念。42現(xiàn)在是42頁\一共有64頁\編輯于星期一如果一個(gè)類的聲明中有abstract修飾符,那么該類就成為抽象類。格式:[訪問權(quán)限]abstractclass類名{……}例如:將前面Shape類聲明為抽象類: abstractclassShape{……}◎說明:抽象類不能進(jìn)行實(shí)例化,否則出現(xiàn)編譯錯(cuò)誤;通常,一個(gè)抽象類至少定義一個(gè)抽象方法,但并不是說非要定義一個(gè)抽象方法,即使類體沒有一個(gè)抽象方法也是允許;當(dāng)一個(gè)類中包含有抽象方法時(shí),該類一定要聲明為抽象類;43現(xiàn)在是43頁\一共有64頁\編輯于星期一◎說明:(續(xù))當(dāng)子類繼承了一個(gè)抽象類時(shí),必須實(shí)現(xiàn)該抽象類中定義的全部抽象方法,否則必須聲明為抽象類;當(dāng)類實(shí)現(xiàn)了一個(gè)接口,但并沒有實(shí)現(xiàn)該接口的所有方法時(shí),該類必須聲明為抽象類,否則出錯(cuò);抽象方法不能被private、final或static修飾。為什么? (抽象方法必須被子類所覆蓋,如果說明為private,則外部無法訪問,覆蓋也無從談起。若說明為Static,即是不創(chuàng)建對象也能訪問:類名.方法名()
,這要求給出方法體,但與抽象方法的定義相矛盾。)問題:以下哪個(gè)是抽象方法的正確形式?(1)abstarctvoidexample()(2)abstarctvoidexample(){}(3)staticabstarctvoidexample()(4)finalabstarctvoidexample()(1)44現(xiàn)在是44頁\一共有64頁\編輯于星期一抽象類與具體類的比較
45現(xiàn)在是45頁\一共有64頁\編輯于星期一抽象類引用
◎雖然不能實(shí)例化抽象類,但可以創(chuàng)建它的引用。Java支持多態(tài)性,允許通過父類引用來引用類的對象。//使用抽象類引用的例子abstractclassA{ //抽象類 abstractvoidm1(); //抽象方法}classBextendsA{
voidm1(){
System.out.println("Inm1.");} //實(shí)現(xiàn)了m1()方法 voidm2(){
System.out.println("Inm2.");
}} publicclassAbstractRef{ publicstaticvoidmain(Stringargs[]){ Bb=newB();
Aa=b; //父類引用 a.m1(); }}程序運(yùn)行結(jié)果:Inm1.46現(xiàn)在是46頁\一共有64頁\編輯于星期一接口(interface) 如果一個(gè)抽象類中的所有方法都是抽象的,可以采用另一種方式——“接口”來定義。接口的概念接口是抽象方法和常量值的定義的集合。從本質(zhì)上講,接口是一種特殊的抽象類,這種抽象類中只包含常量和方法的定義,而沒有方法的實(shí)現(xiàn)。從語法上看,接口是一種與“類”很相似的結(jié)構(gòu),只是接口中的所有方法都是抽象的,只有聲明、沒有方法體。接口聲明的關(guān)鍵字是interface。47現(xiàn)在是47頁\一共有64頁\編輯于星期一什么是接口?認(rèn)識一下接口◎接口特性:接口不可以被實(shí)例化實(shí)現(xiàn)類必須實(shí)現(xiàn)接口的所有方法實(shí)現(xiàn)類可以實(shí)現(xiàn)多個(gè)接口接口中的變量都是靜態(tài)常量publicinterfaceMyInterface
{publicvoidfoo();//其他方法}所有方法都是:publicabstract抽象類除外Java中的多繼承常作為類型使用現(xiàn)在是48頁\一共有64頁\編輯于星期一接口的聲明格式:[權(quán)限修飾符]interface接口名
[extends父接口列表]{ //抽象方法和靜態(tài)常量}例如:publicinterfaceRunner{ intid=1; publicvoidstart(); publicvoidrun(); publicvoidstop(); }49現(xiàn)在是49頁\一共有64頁\編輯于星期一說明:接口的修飾符可以是public或缺??;接口中的方法都是抽象的和公有(public)的,僅有方法說明,沒有方法體;接口中的常量默認(rèn)是公共的、靜態(tài)的和最終的,在聲明時(shí)一般不需要用public、static、final。接口關(guān)心的是“做什么”,不關(guān)心“怎樣做”,即是聲明一種規(guī)范,而不是實(shí)現(xiàn);生活中類似的例子:電腦主板中的各種插槽等;通過接口可以間接實(shí)現(xiàn)多重繼承。50現(xiàn)在是50頁\一共有64頁\編輯于星期一接口的實(shí)現(xiàn) 接口規(guī)定了類的“原型”,具體實(shí)現(xiàn)由實(shí)現(xiàn)該接口的類來完成,格式如下:[修飾符]class類名[extends父類][implements接口1,接口2,…]{ …… //包含對接口的所有方法的實(shí)現(xiàn)}//例子publicclassPersonimplementsRunner{
publicvoidstart(){
//準(zhǔn)備工作:彎腰、蹬腿、咬牙、瞪眼
//開跑
}
publicvoidrun(){ //擺動(dòng)手臂 //維持直線方向
} publicvoidstop(){ //減速直至停止、喝水。
}}51現(xiàn)在是51頁\一共有64頁\編輯于星期一說明:一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,從而達(dá)到多重繼承的目的;多個(gè)無關(guān)的類可以實(shí)現(xiàn)同一個(gè)接口;通過接口可以實(shí)現(xiàn)不相關(guān)類的相同行為,而不需要考慮這些類之間的層次關(guān)系;一個(gè)具體類實(shí)現(xiàn)接口時(shí),必須實(shí)現(xiàn)接口中的所有抽象方法;當(dāng)一個(gè)類未實(shí)現(xiàn)接口中的所有抽象方法時(shí),應(yīng)聲明為抽象類;類在實(shí)現(xiàn)某個(gè)接口的抽象方法時(shí),必須使用完全相同的方法頭,例如:接口定義中通常省略public修飾符,但在實(shí)現(xiàn)抽象方法時(shí)必須顯式使用public修飾符;通過接口可以指明多個(gè)類需要實(shí)現(xiàn)的方法;與繼承關(guān)系類似,接口與實(shí)現(xiàn)類之間存在多態(tài)性。???52現(xiàn)在是52頁\一共有64頁\編輯于星期一下面類A的定義形式中,哪一個(gè)是正確的?(1)classAextendsB,C{ ……}(2)classAimplementsB,C{ ……}(3)classAextendsBimplementsC{ ……}(4)classAextendsBimplementsC,D{ ……}答案:(2)、(3)、(4)53現(xiàn)在是53頁\一共有64頁\編輯于星期一通過接口可以實(shí)現(xiàn)不相關(guān)類的相同行為<<interface>>Runner+start()+run()+stop()Person+start()+run()+stop()+dance()Car+start()+run()+stop()+fillFuel()+crack()Bird+start()+run()+stop()+fly()54現(xiàn)在是54頁\一共有64頁\編輯于星期一//接口應(yīng)用例子interfaceRunner{ //接口1 publicvoidrun();}interfaceSwimmer{ //接口2 publicvoidswim();}abstractclassAnimal{ //抽象類,去掉關(guān)鍵字abstract是否可行? publicabstractvoideat();}classPersonextendsAnimalimplementsRunner,Swimmer{//繼承類,實(shí)現(xiàn)接口 publicvoidrun(){ System.out.println("我是飛毛腿,跑步速度極快!"); } publicvoidswim(){ System.out.println("我游泳技術(shù)很好,會蛙泳、自由泳、仰泳、蝶泳..."); } publicvoideat(){ System.out.println("我牙好胃好,吃啥都香!"); }}55現(xiàn)在是55頁\一共有64頁\編輯于星期一publicclassInterfaceTest{ publicstaticvoidmain(Stringargs[]){ InterfaceTestt=newInterfaceTest();
Personp=newPerson(); t.m1(p);
//接口回調(diào),下同
t.m2(p); t.m3(p); } publicvoidm1(Runnerr){r.run();} //接口作參數(shù),下同 publicv
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024短期汽車租賃服務(wù)合同版B版
- 動(dòng)物行為學(xué)知到智慧樹章節(jié)測試課后答案2024年秋浙江農(nóng)林大學(xué)
- 2025年度博物館場地租賃及展覽展示服務(wù)協(xié)議3篇
- 2024年數(shù)字政府白皮書一體化政務(wù)大數(shù)據(jù)分冊
- 船舶制造塔吊租賃協(xié)議模板
- 鋼結(jié)構(gòu)圖書館鋼架焊接施工合同
- 港口曬場施工協(xié)議
- 礦業(yè)安全監(jiān)督員租賃協(xié)議
- 酒吧休閑魚池租賃合同
- 食品加工設(shè)備維修機(jī)井合同
- 技術(shù)服務(wù)合同-英文版模板
- 軍營防襲擊應(yīng)急預(yù)案演練
- 北京同仁醫(yī)院全面預(yù)算管理
- 附件1:上海市新增醫(yī)療服務(wù)項(xiàng)目價(jià)格申請受理表
- 法定代表人身份證明書-模板
- 反射療法師理論考試復(fù)習(xí)題庫匯總(含答案)
- word版改善就醫(yī)感受提升患者體驗(yàn)評估操作手冊2023版
- GB/T 43218-2023煤炭測硫儀性能驗(yàn)收導(dǎo)則
- 可許則許-陳海量居士
- 勘察設(shè)計(jì)招標(biāo)評分標(biāo)準(zhǔn)
- 化學(xué)倉應(yīng)急預(yù)案
評論
0/150
提交評論