《Java語言程序設(shè)計(jì)案例教程》課件第6章_第1頁(yè)
《Java語言程序設(shè)計(jì)案例教程》課件第6章_第2頁(yè)
《Java語言程序設(shè)計(jì)案例教程》課件第6章_第3頁(yè)
《Java語言程序設(shè)計(jì)案例教程》課件第6章_第4頁(yè)
《Java語言程序設(shè)計(jì)案例教程》課件第6章_第5頁(yè)
已閱讀5頁(yè),還剩125頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第6章多態(tài)性6.1多態(tài)性的概念6.2抽象類6.3接口6.4JAR文檔第6章多態(tài)性學(xué)習(xí)目標(biāo)

理解Java語言多態(tài)性的概念;

掌握抽象類的概念和定義方法;

理解接口和接口的實(shí)現(xiàn)技術(shù)。從字面意思來說,多態(tài)(polymorphism)就是指“多種形態(tài)”。那么,在Java中什么量可以有多種形態(tài)呢?前面我們介紹的方法重載中,同一個(gè)方法名根據(jù)需要在程序中可以定義多個(gè)不同的方法體,這就是Java語言中多種形態(tài)的方法。因此,簡(jiǎn)單地說,多態(tài)就是指同名但形態(tài)(即功能)不同的方法。多態(tài)性提高了程序設(shè)計(jì)的抽象性和簡(jiǎn)潔性,是面向?qū)ο蟪绦蛟O(shè)計(jì)的一個(gè)重要特征。本章介紹與實(shí)現(xiàn)多態(tài)有關(guān)的Java概念和技術(shù),主要內(nèi)容有多態(tài)的概念、抽象類與多態(tài)、接口與多態(tài)。6.1多態(tài)性的概念在第5章介紹類的層次結(jié)構(gòu)時(shí)我們說過,一個(gè)父類的引用變量可以指向一個(gè)子類的實(shí)例對(duì)象,而一個(gè)父類可能有多個(gè)子類。如我們說“狗是一種哺乳動(dòng)物”,也可以說“馬是一種哺乳動(dòng)物”,“貓是一種哺乳動(dòng)物”,等等,這里的“哺乳動(dòng)物”是父類(如用Mammal表示),而狗、馬、貓等是“哺乳動(dòng)物”的子類。有如下的類定義:publicclassMammal{…}classDogextendsMammal{…}classHorseextendsMammal{…}classCatextendsMammal{…}當(dāng)我們說明了如下的一個(gè)“哺乳動(dòng)物類”的引用animal時(shí):Mammalanimal;

animal可能在程序運(yùn)行的不同時(shí)刻指向了Mammal子類的不同對(duì)象。例如,在某個(gè)時(shí)刻可能指向的是一個(gè)狗類(Dog)的實(shí)例對(duì)象,而在另外一個(gè)時(shí)刻可能指向的是貓類(Cat)的實(shí)例對(duì)象或馬類(Horse)的實(shí)例對(duì)象。像animal這樣在不同時(shí)段內(nèi)可以指向不同類型對(duì)象的引用,就是多態(tài)性的引用。Java的多態(tài)性就是指方法的多態(tài)和引用的多態(tài)。下面介紹有關(guān)多態(tài)的基本知識(shí)。6.1.1多態(tài)的基本知識(shí)在Java語言中,多態(tài)性分為兩種類型。

1.由方法多態(tài)引發(fā)的編譯時(shí)多態(tài)性編譯時(shí)多態(tài)性是由方法重載實(shí)現(xiàn)的。前面介紹過,重載是指在同一個(gè)類(也可以是子類與父類)中,同一個(gè)方法名被定義多次,但所采用的形式參數(shù)列表不同(可能是參數(shù)的個(gè)數(shù)、類型或順序不同)。在重載方法的編譯階段,編譯器會(huì)根據(jù)所調(diào)用方法參數(shù)的不同,具體來確定要調(diào)用的方法。如下面的程序中定義了一個(gè)類A:classA{…A(){…}A(intx){…}A(intx,inty){…}…}類A中定義了三個(gè)重載的構(gòu)造方法,則在實(shí)例化一個(gè)對(duì)象時(shí),會(huì)根據(jù)構(gòu)造方法中實(shí)參的類型與個(gè)數(shù)確定調(diào)用類A中的哪個(gè)構(gòu)造方法。如程序中有下面一條語句:Aa=newA(12);則編譯時(shí),系統(tǒng)就可以確定該處要調(diào)用類A中有一個(gè)參數(shù)的構(gòu)造方法。

2.由引用多態(tài)引發(fā)的運(yùn)行時(shí)多態(tài)性由于子類繼承了父類所有的屬性,因此子類對(duì)象可以作為父類對(duì)象使用。程序中凡是使用父類對(duì)象的地方,都可以用子類對(duì)象來代替,因此,如果說明了一個(gè)父類的引用,則這個(gè)引用就是多態(tài)性的引用。對(duì)于多態(tài)性的一個(gè)引用,調(diào)用方法的原則是:Java運(yùn)行時(shí),系統(tǒng)根據(jù)調(diào)用該方法的實(shí)例來決定調(diào)用哪個(gè)方法。對(duì)子類的一個(gè)實(shí)例,如果子類重寫了父類的方法,則運(yùn)行時(shí)系統(tǒng)調(diào)用子類的方法;如果子類繼承了父類的方法(未重寫),則運(yùn)行時(shí)系統(tǒng)調(diào)用父類的方法。編譯時(shí)多態(tài)性比較簡(jiǎn)單,本章我們主要討論運(yùn)行時(shí)多態(tài)性。6.1.2【案例6-1】吃水果

1.案例描述一天,小明的媽媽買了一籃子水果(Fruit),有香蕉(Banana)、蘋果(Apple)和椰子(Coconut)。小明在吃這些水果時(shí),如果拿到了一個(gè)香蕉就要“剝了皮吃”,如果拿到了一個(gè)蘋果就要“削了皮吃”,如果拿到了一個(gè)椰子就要“鉆一個(gè)孔來喝”?,F(xiàn)要求設(shè)計(jì)一個(gè)程序,模擬小明選擇水果和吃水果的過程。

2.案例效果案例程序的執(zhí)行效果如圖6-1所示。圖6-1案例6-1的執(zhí)行效果

3.技術(shù)分析該問題域中,香蕉(Banana)、蘋果(Apple)和椰子(Coconut)是不同種類的水果(Fruit),它們都是水果里的一個(gè)子類,因此這里的父類是水果類(Fruit),子類是香蕉類(Banana)、蘋果類(Apple)和椰子類(Coconut)。水果都可以吃,所以水果類中要定義一個(gè)“吃”水果(eat)的方法。

4.程序解析下面是該案例的程序代碼:01//******************************************02//案例:6-103//程序名:EatFruit.java04//功能:模擬吃水果的程序05//******************************************0607importjava.util.Scanner;0809//水果類10classFruit{11 voideat(){}12}1314//蘋果類15classAppleextendsFruit{16 voideat(){17 System.out.println("蘋果,要削了皮吃!");18 }19}2021//香蕉類22classBananaextendsFruit{23 voideat(){24 System.out.println("香蕉,要?jiǎng)兞似こ?");25 }26}2728//椰子類29classCoconutextendsFruit{30 voideat(){31 System.out.println("椰子,要鉆一個(gè)孔來喝!");32 }33}343536classEatFruit{ 37 38 //選擇所要吃的水果39 staticvoidchooseFruit(Fruit[]f){40 intfruitType;41 Scannersc=newScanner(System.in);42 43 System.out.println("");44 System.out.println(“請(qǐng)選擇你要吃的水果:\n1.蘋果

\t2.香蕉\t3.椰子");45 System.out.println("");46 47 for(inti=1;i<=f.length;i++){48 System.out.print("請(qǐng)選擇要吃的第"+i+"個(gè)水果:");49 50 //如果選擇的水果不正確,要重新選擇51 while(true){52 fruitType=sc.nextInt();53 if((fruitType==1)||(fruitType==2)||(fruitType==3))54 break;55 else System.out.print("請(qǐng)重新選擇要吃的第"+i+“個(gè)水果:");56 }57 58 //根據(jù)所選擇的水果,創(chuàng)建相應(yīng)的實(shí)例59 switch(fruitType){60 case1:f[i-1]=newApple();break;61 case2:f[i-1]=newBanana();break;62 case3:f[i-1]=newCoconut();break;63 }64 }65 }66 67 //開始吃水果68 staticvoidstartEating(Fruit[]f){69 System.out.println("");70 for(inti=1;i<=f.length;i++){71 System.out.print("第"+i+"個(gè)水果是");72 f[i-1].eat();73 }74 }75 76 77 publicstaticvoidmain(String[]args){78 Fruit[]f=newFruit[6];79 chooseFruit(f);80 startEating(f);81 }82}該程序中,第10~12行定義了一個(gè)水果類Fruit,在其后面定義的Apple類、Banana類和Coconut類都繼承了Fruit類,即這3個(gè)類都是Fruit類的子類,在每個(gè)子類中都重寫了父類中的eat方法。父類中的eat方法體為空,因?yàn)镕riut類中只知道每一種水果都可以吃,但具體要吃什么水果是不知道的,所以吃什么水果只能在子類中根據(jù)具體情況重新定義。在本程序中,定義了一個(gè)吃水果的類EatFruit。該類的代碼顯得比較復(fù)雜些,其中39~65行定義了一個(gè)選擇所要吃水果的方法chooseFruit,通過該方法可以將所選擇要吃的水果存放在一個(gè)數(shù)組中。該數(shù)組的每個(gè)元素是一個(gè)對(duì)象,具體根據(jù)所選擇水果種類的不同可以是Apple類、Banana類或Coconut類的實(shí)例對(duì)象,這個(gè)過程是由程序59~63行的一個(gè)switch語句來實(shí)現(xiàn)的。在該switch語句中根據(jù)所選擇水果的不同,分別創(chuàng)建了Apple類、Banana類或Coconut類的對(duì)象。在EatFruit類中,最關(guān)鍵的是68~74行定義的吃水果的方法startEating,正是該方法根據(jù)所選擇水果的不同,調(diào)用了不同的吃水果的方法,完成了所謂多態(tài)性方法的調(diào)用。程序中70~73行是一個(gè)for循環(huán)語句,其循環(huán)體中的“f[i-1].eat()”語句,會(huì)根據(jù)數(shù)組元素f[i-1]中存放的引用對(duì)象是Apple類、Banana類或Coconut類的實(shí)例,來調(diào)用其相應(yīng)子類中定義的eat()方法。這就是本節(jié)要重點(diǎn)介紹的內(nèi)容。一個(gè)父類的引用,會(huì)根據(jù)當(dāng)前所指向?qū)ο蟮牟煌?,調(diào)用相應(yīng)子類中被重寫的方法,這就是所謂由引用多態(tài)引發(fā)的運(yùn)行時(shí)多態(tài)性。運(yùn)行時(shí)多態(tài)性在程序被編譯時(shí),不能確定一個(gè)多態(tài)引用所要調(diào)用的方法,只有在程序運(yùn)行時(shí)才能根據(jù)引用所指向?qū)ο蟮念悂泶_定被調(diào)用的方法。

EatFruit類中定義的方法其下標(biāo)都為“i-1”,是因?yàn)閒or循環(huán)中的循環(huán)變量i都從1開始,而一個(gè)數(shù)據(jù)的下標(biāo)是從0開始的。在main方法中,78行定義了一個(gè)元素類型是Fruit類的數(shù)組f,f中共有6個(gè)下標(biāo)元素。79行調(diào)用chooseFruit(f)方法將所選擇的水果存放在f數(shù)組中,80行調(diào)用startEating(f)方法開始吃水果。要注意的是,這兩個(gè)方法的參數(shù)都是數(shù)組f,在調(diào)用chooseFruit(f)方法前,f數(shù)組中沒有存放任何元素;當(dāng)該方法執(zhí)行完成后,將所選擇的水果存放在f數(shù)組中,這樣在調(diào)用startEating(f)方法吃水果時(shí),f數(shù)組中已經(jīng)存放了所選擇的水果。當(dāng)數(shù)組中的元素類型為對(duì)象時(shí),會(huì)令初學(xué)者比較困惑。下面對(duì)這個(gè)問題進(jìn)行說明。程序中78行的語句是“Fruit[]f=newFruit[6]”,該語句執(zhí)行后的情況如圖6-2所示。該語句中的“Fruit[]f”聲明只完成圖6-2(a)所示的內(nèi)容,即只創(chuàng)建了一個(gè)數(shù)組型引用變量f?!皀ewFruit[6]”完成圖6-2(b)所示的內(nèi)容,即為引用f在內(nèi)存中創(chuàng)建6個(gè)指向Fruit型的數(shù)組元素,每個(gè)數(shù)組元素是一個(gè)Fruit型的對(duì)象。程序中60~62行的語句為創(chuàng)建每個(gè)數(shù)組元素對(duì)象(即下標(biāo)變量)所指向的對(duì)象實(shí)例,如圖6-2(c)所示。EatFruit類中的方法為了在程序中不實(shí)例化對(duì)象就可以調(diào)用,所以都聲明成了靜態(tài)方法(static)。圖6-2數(shù)組的元素為對(duì)象時(shí)的創(chuàng)建過程6.1.3【相關(guān)知識(shí)】數(shù)據(jù)的輸入與格式化輸出在一個(gè)程序中,經(jīng)常要從鍵盤上給某些變量輸入數(shù)據(jù),輸入的數(shù)據(jù)經(jīng)過程序處理后,又要以某種格式進(jìn)行輸出。下面介紹Java語言中與數(shù)據(jù)輸入和輸出有關(guān)的知識(shí)。

1.輸入的數(shù)據(jù)案例6-1程序第39行定義的chooseFruit(Fruit[]f)方法中,在第41行使用了Scanner類。Scanner類是Java5.0在java.util包中新增加的一個(gè)類,該類用于輸入數(shù)據(jù),其數(shù)據(jù)來源可以是文件、字符串或鍵盤等。使用Scanner類從鍵盤上輸入數(shù)據(jù)的步驟是:

(1)創(chuàng)建一個(gè)該類的對(duì)象,并指定輸入源。如果要從鍵盤上輸入數(shù)據(jù),常用類似于如下的格式:Scannersc=newScanner(System.in);其中,System.in在Java語言中表示標(biāo)準(zhǔn)輸入設(shè)備(另外,經(jīng)常使用System.out表示標(biāo)準(zhǔn)輸出設(shè)備,一般指顯示器),其實(shí)就是鍵盤,表示要從鍵盤上輸入數(shù)據(jù)。

Scanner對(duì)象一般使用空格符(包括空格、Tab鍵和換行符)分隔輸入的內(nèi)容。

(2)使用Scanner類提供的方法從數(shù)據(jù)源取得數(shù)據(jù)。Scanner類中定義的nextXXX方法將輸入內(nèi)容中的數(shù)據(jù)取出并轉(zhuǎn)換為不同類型的值。常用的方法有:●?nextBoolean():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)布爾值,并返回該值;●?nextByte():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)byte類型的值,并返回該值;●?nextDouble():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)double類型的值,并返回該值;●?nextFloat():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)float類型的值,并返回該值;●?nextInt():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)int類型的值,并返回該值;●?nextLong():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)long類型的值,并返回該值;●?nextShort():將掃描到的內(nèi)容轉(zhuǎn)換為一個(gè)short類型的值,并返回該值;●?nextLine():讀取一行內(nèi)容,并以字符串的形式返回該值。例如,以下代碼可使用戶從鍵盤上(System.in)讀取一個(gè)整數(shù),并將讀到的數(shù)據(jù)保存在變量i中:Scannersc=newScanner(System.in);inti=sc.nextInt();

2.格式化輸出數(shù)據(jù)程序中要輸出的數(shù)據(jù)通常要按特定格式輸出,如計(jì)算出的商品總價(jià)要以貨幣格式輸出,產(chǎn)品的合格率要以百分?jǐn)?shù)格式輸出等。在Java語言的java.text包中,提供的DecimalFormat類可以將數(shù)據(jù)按要求的格式進(jìn)行輸出。下面舉例說明DecimalFormat類的用法。

(1)創(chuàng)建輸出格式類的對(duì)象,并指定輸出格式。使用DecimalFormat類格式化輸出數(shù)據(jù)時(shí),先要?jiǎng)?chuàng)建一個(gè)DecimalFormat類的對(duì)象,并在構(gòu)造方法的參數(shù)中以字符串的形式說明輸出數(shù)據(jù)的格式(這個(gè)說明輸出數(shù)據(jù)格式的字符串也叫掩碼)。例如:

DecimalFormatdf1=newDecimalFormat("¥0.00");掩碼“¥0.00”中的¥表示輸出數(shù)據(jù)的最前面要加一個(gè)貨幣符號(hào)¥,“0.00”表示小數(shù)點(diǎn)的左邊至少要有一位數(shù)字,而小數(shù)點(diǎn)的右邊有且只能有兩位數(shù)字。如果小數(shù)點(diǎn)后面的數(shù)字多于兩位,則將小數(shù)點(diǎn)后的第3位數(shù)字四舍五入;如果小數(shù)點(diǎn)后面的數(shù)字少于兩位,則用0補(bǔ)齊。下面創(chuàng)建的格式化輸出對(duì)象df2將在輸出數(shù)據(jù)的前面加“產(chǎn)品的合格率為:”字符串,并將數(shù)據(jù)以百分?jǐn)?shù)的格式輸出:DecimalFormatdf2=newDecimalFormat("產(chǎn)品的合格率為:0.00%");下面創(chuàng)建的格式化輸出對(duì)象df3將在輸出數(shù)據(jù)的小數(shù)點(diǎn)后面保留3位小數(shù),“#”表示將為輸出的數(shù)據(jù)保留位置,但會(huì)取消所有的前導(dǎo)0,小數(shù)點(diǎn)前面的數(shù)據(jù)每3位用“,”分隔,并在小數(shù)點(diǎn)前面至少要有一個(gè)數(shù)字:DecimalFormatdf3=newDecimalFormat("#,##0.000");

(2)使用DecimalFormat類的format方法將數(shù)據(jù)按指定格式輸出。如要將345.3789按df1格式輸出,則可以寫成:

System.out.println(df1.format(345.3789));也可以將按df1格式輸出的數(shù)據(jù)賦給一個(gè)字符串變量:

Strings=df1.format(345.3789);如要將345.3789按df2格式輸出,則可以寫成:

System.out.println(df2.format(345.3789));下面是格式化輸出的一個(gè)示例程序:01importjava.text.DecimalFormat;//引入格式化輸出類02classDataFormat{03 publicstaticvoidmain(String[]args){04 DecimalFormatdf1=newDecimalFormat("¥0.00");05 DecimalFormatdf2=newDecimalFormat(“產(chǎn)品的合格率為:0.00%");06 DecimalFormatdf3=new

DecimalFormat("#,##0.000");07 Strings=df2.format(0.72341);08 System.out.println(df1.format(234.237234));09 System.out.println(df2.format(0.876767));10 System.out.println(df3.format(234523450.237234));11 System.out.println(s);12 }13}程序的執(zhí)行結(jié)果如圖6-3所示。圖6-3示例程序格式化輸出的結(jié)果6.2抽象類案例6-1中的Fruit類定義了一個(gè)名為eat的方法,水果可以吃,但不同的水果有不同的吃法,因此Fruit類中不能確定吃水果的具體方法,只能在Fruit類的子類中具體定義。Fruit類中定義eat方法的目的只是告訴Fruit類的子類,對(duì)父類的eat方法要根據(jù)具體情況進(jìn)行重寫。像這樣一個(gè)方法在定義時(shí),不能確定其方法體的具體內(nèi)容,在Java語言中可以定義為抽象方法。如果一個(gè)類中有抽象方法,則這個(gè)類應(yīng)該定義為抽象類。本節(jié)介紹抽象方法與抽象類的概念,并說明抽象類與多態(tài)的關(guān)系。6.2.1抽象類的基本知識(shí)

1.抽象方法像Fruit類中的eat方法,其方法體為空,這樣的方法只是告訴編譯器在子類中要重寫該方法,這時(shí)可將該方法定義為抽象方法。在Java語言中,抽象方法要用abstract關(guān)鍵字來修飾,一個(gè)抽象方法沒有方法體,只有方法的聲明部分(即方法頭)。抽象方法的定義格式是:abstract返回類型抽象方法名([參數(shù)列表]);注意:抽象方法在參數(shù)列表的后面使用“;”代替了方法體。一個(gè)子類繼承了父類時(shí),父類中定義的抽象方法要在子類中實(shí)現(xiàn)。子類中實(shí)現(xiàn)父類定義的抽象方法時(shí),其方法名、返回值和參數(shù)類型要與父類中抽象方法的方法名、返回值和參數(shù)類型相一致。由于一個(gè)父類可能有多個(gè)子類,而每個(gè)子類對(duì)父類中的同一個(gè)抽象方法給出了不同的實(shí)現(xiàn)過程,這樣就會(huì)出現(xiàn)同一個(gè)名稱、同一種類型的返回值在不同的子類中實(shí)現(xiàn)的方法體不同的情況,這正是實(shí)現(xiàn)多態(tài)的基礎(chǔ)。注意1:由于抽象方法在子類中要重新定義,因此不能將其聲明為靜態(tài)方法,即不能用static修飾。注意2:一個(gè)類的構(gòu)造方法不能聲明成抽象方法。

2.抽象類在Java語言中,如果一個(gè)類中定義了抽象方法,則這個(gè)類一定要定義成抽象類。一個(gè)抽象類用abstract關(guān)鍵字修飾。定義抽象類的格式如下:abstractclass抽象類名{…}抽象類必須被繼承,抽象方法必須在子類中被重寫,除非這個(gè)子類也是一個(gè)抽象類。注意1:抽象類中可以包含非抽象的方法。注意2:一個(gè)抽象類不一定要包含抽象方法,即使沒有一個(gè)抽象方法的類,也可以聲明成抽象類。注意3:若類中包含了抽象方法,則該類必須定義為抽象類。注意4:抽象類不能用來實(shí)例化對(duì)象。在學(xué)習(xí)了抽象類以后,案例6-1中的Fruit類應(yīng)該定義為一個(gè)抽象類,定義方法如下:abstractclassFruit{ abstractvoideat();}要注意,方法eat應(yīng)以分號(hào)結(jié)束。將Fruit類改為抽象類以后,案例6-1的執(zhí)行結(jié)果不變。因?yàn)镕ruit類為抽象類,不能用來實(shí)例化對(duì)象,所以程序中不能有類似于如下的語句:Fruitf=newFruit();在Fruit類的子類Apple、Banana和Coconut中,重寫的方法名eat之前不能再使用abstract修飾,否則會(huì)出現(xiàn)編譯錯(cuò)誤。抽象類處在類層次結(jié)構(gòu)的較高層,其優(yōu)點(diǎn)是可以概括某類事物的共同屬性,在子類中只需簡(jiǎn)單地描述其特有的內(nèi)容即可,這樣可以簡(jiǎn)化程序的設(shè)計(jì)。

3.抽象類的繼承抽象類只能作為基類使用,因此必須被子類繼承。如果一個(gè)類繼承的是一個(gè)抽象類,則該類中要實(shí)現(xiàn)抽象類中的抽象方法。當(dāng)然,對(duì)于抽象類中的非抽象方法也可以在子類中進(jìn)行覆蓋。當(dāng)子類對(duì)父類中的抽象方法不進(jìn)行重寫時(shí),這個(gè)子類就只能成為一個(gè)抽象類,這種情況比較少。下面是一個(gè)抽象類繼承的示例程序:01abstractclassA{02 abstractvoidf();03 A(){04 System.out.println("Aconstructor");05 }06}0708abstractclassBextendsA{09 B(){10 System.out.println("Bconstructor");11 }12}1314classCextendsB{15 C(){16 System.out.println("Cconstructor");17 }18 voidf(){19 System.out.println("methodf()ofclassC.");20 } 21}2223classTestAbstractClass{24 publicstaticvoidmain(String[]args){25 Aa=newC();26 a.f();27 }28}程序中定義了一個(gè)抽象類A,類A中定義了一個(gè)抽象方法f()和一個(gè)無參的構(gòu)造方法A()。類B繼承了類A,但是沒有實(shí)現(xiàn)基類A中的抽象方法f(),所以類B只能定義成一個(gè)抽象類。類C繼承了類B,并且實(shí)現(xiàn)了類B從父類A中繼承的抽象方法f(),類C定義成了一個(gè)非抽象的類,它可以用來實(shí)例化對(duì)象。25行聲明了一個(gè)A類的引用,但實(shí)例化成了其間接子類C的對(duì)象。26行調(diào)用了f()方法。該程序的輸出內(nèi)容如下:AconstructorBconstructorCconstructormethodf()ofclassC.從該例可以看出,在程序中可以聲明一個(gè)抽象類的引用,但一定要將其實(shí)例化成子類的一個(gè)對(duì)象。由于一個(gè)抽象類可能有多個(gè)子類,因此抽象類的引用可以指向不同子類的對(duì)象,這樣抽象類的這個(gè)引用就是一個(gè)多形態(tài)的引用。這個(gè)引用在調(diào)用子類中被重寫的方法時(shí),會(huì)根據(jù)該引用當(dāng)前所指向?qū)ο箢愋偷牟煌{(diào)用不同類中的那個(gè)方法。這就是由抽象類引起的多態(tài)。注意:抽象類的構(gòu)造方法不能是抽象的。6.2.2【案例6-2】定義平面幾何形狀類

1.案例描述在一個(gè)數(shù)學(xué)軟件包的開發(fā)過程中,要求軟件包中有求常見平面圖形(如三角形、圓、矩形和正方形等)面積的功能,編寫程序?qū)崿F(xiàn)該功能。

2.案例效果該案例程序的執(zhí)行結(jié)果如圖6-4所示。圖6-4案例6-2的執(zhí)行結(jié)果

3.技術(shù)分析各種平面圖形都可以求出其面積,但對(duì)于不同的形狀,其求面積的方法不同,因此可以定義一個(gè)平面圖形形狀類Shape。Shape類中有一個(gè)求面積的抽象方法(area),之所以定義為抽象方法,是因?yàn)椴煌钠矫鎴D形其求面積的方法不同。圓(Circle)、矩形(Rectangle)和三角形(Triangle)是不同的形狀,它們都是Shape的子類,而正方形(Square)是矩形(Rectangle)中的一種特殊類型,因此正方形是矩形的子類,如圖6-5所示。抽象類的類名在類圖中要用斜體表示,以區(qū)別于普通的類。圖6-5幾何形狀的類層次結(jié)構(gòu)

4.程序解析下面是案例6-2的程序代碼:001//******************************************002//案例:6-2003//程序名:TestShape.java004//功能:求各種形狀的面積005//******************************************006007importjava.text.*;008009//形狀抽象類010abstractclassShape{011 publicabstractdoublearea();012}013014//圓類015classCircleextendsShape{016 privatedoubler;017 018 publicCircle(doubler){019 this.r=r;020 }021 022 publicdoublearea(){023 return3.14*r*r;024 }025 026 publicStringtoString(){027 return"圓的半徑是:"+r;028 }029}030031//三角形類032classTriangleextendsShape{033 privatedoublea,b,c;034 035 Triangle(doublea,doubleb,doublec){036 this.a=a;037 this.b=b;038 this.c=c;039 }040 041 publicbooleanisTriangle(){042 return(a+b>c)&&(a+c>b)&&(b+c>a);043 }044 045 publicdoublearea(){046 doubles=0.5*(a+b+c);047 returnMath.sqrt(s*(s-a)*(s-a)*(s-c));048 }049 050 publicStringtoString(){051 return"三角形的三個(gè)邊長(zhǎng)分別是:"+a+","+b+","+c;052 }053}054055//矩形類056classRectangleextendsShape{057 protecteddoublewidth,height;058 059 publicRectangle(doublewidth,doubleheight){060 this.width=width;061 this.height=height;062 }063 064 publicdoublearea(){065 returnwidth*height;066 }067 068 publicStringtoString(){069 return"矩形的寬是:"+width+",高是:"+height;070 }071}072073//正方形類074classSquareextendsRectangle{075 Square(doublewidth){076 super(width,width);077 }078 079 publicdoublearea(){080 returnsuper.area();081 }082 083 publicStringtoString(){084 return"正方形的邊長(zhǎng)是:"+width;085 }086}087088//測(cè)試類089publicclassTestShape{090 publicstaticvoidmain(String[]args){091 Shape[]shapes=newShape[6];092 shapes[0]=newTriangle(23.2,45.4,4.7);093 shapes[1]=newCircle(23.4);094 shapes[2]=newRectangle(23.4,56.0);095 shapes[3]=newSquare(23.4);096 shapes[4]=newTriangle(23.2,35.4,23.7);097 shapes[5]=newCircle(2.0);098 099 DecimalFormatdf=newDecimalFormat("#0.00");100 101 for(inti=0;i<shapes.length;i++){102 if(shapes[i]instanceofTriangle){103 Trianglet=(Triangle)shapes[i];104 if(!t.isTriangle()){105 System.out.println("所給3個(gè)邊構(gòu)不成一個(gè)三角形!“

+shapes[i]);106 continue;107 }108 }109 System.out.println(shapes[i]+",面積是:"+

df.format(shapes[i].area()));110 }111 }112}在案例的010~012行定義了一個(gè)抽象類Shape,該類中定義了一個(gè)抽象方法area,表示任何一個(gè)平面幾何形狀都可以求其面積。015~071行定義了形狀類的3個(gè)子類,分別表示一種具體的幾何形狀,這些子類中都重寫了父類Shape中的抽象方法area,并在每個(gè)子類中重寫了Object類的toString方法。程序中074~086行定義的正方形類Square繼承了矩形類Rectangle。075行定義的構(gòu)造方法Square(doublewidth)調(diào)用了父類的構(gòu)造方法,但要注意,由于正方形只需知道邊長(zhǎng)即可,因此正方形的構(gòu)造方法只有一個(gè)參數(shù)(即邊長(zhǎng))。076行的super(width,width)表示調(diào)用父類059行定義的構(gòu)造方法,但長(zhǎng)和寬使用了相同的參數(shù)。080行的super.area()表示調(diào)用父類中064行求面積的方法。在測(cè)試類TestShape的091行定義了一個(gè)形狀類的數(shù)組,該數(shù)組有6個(gè)元素。由于Shape是一個(gè)抽象類,盡管在程序中可以聲明抽象類的引用(在這里就是每個(gè)下標(biāo)變量),但絕對(duì)不能創(chuàng)建一個(gè)抽象類的實(shí)例對(duì)象,即在程序中不能有類似于如下的語句:Shape[]shapes=newShape[6]; shapes[0]=newShape();shapes[1]=newShape();這是因?yàn)槌橄箢愔荒苡糜诶^承,不能實(shí)例化對(duì)象。程序的099行創(chuàng)建了一個(gè)格式化輸出對(duì)象df,其中的參數(shù)#0.00表示小數(shù)點(diǎn)后有兩個(gè)數(shù)字,且小數(shù)點(diǎn)前至少有一位數(shù)。在輸出每種形狀的面積時(shí),使用該格式輸出對(duì)象。程序的101~110行是一個(gè)循環(huán)語句,在循環(huán)體中計(jì)算并輸出了存放在數(shù)組shapes中的每個(gè)具體形狀的面積。?其中102行的shapes[i]instanceofTriangle用于測(cè)試shapes[i]中保存的對(duì)象是否為一個(gè)三角形(Triangle),如果是三角形,就要調(diào)用三角形類中041行定義的判斷三個(gè)邊能否構(gòu)成三角形的方法isTriangle,如果所給三個(gè)邊不能構(gòu)成一個(gè)三角形,則不能求面積,用106行的continue語句進(jìn)行下一次循環(huán)。該案例中,多態(tài)性就體現(xiàn)在109行的shapes[i].area()方法調(diào)用上,當(dāng)i取不同的值時(shí),shapes[i]表示不同形狀的對(duì)象,因而系統(tǒng)會(huì)自動(dòng)根據(jù)shapes[i]中所保存對(duì)象的所屬類,調(diào)用相應(yīng)類中求面積的方法,從而實(shí)現(xiàn)了多態(tài)性。6.2.3【相關(guān)知識(shí)】Object類的toString方法在第5章介紹過,Object類是Java語言中所有類的直接或間接父類,因此在Object類中定義的方法會(huì)被所有類繼承。Object類中定義的toString方法常常用來輸出類中的一些信息,如在案例6-2的每個(gè)子類中都重寫了Object類的toString方法,用來輸出與每個(gè)子類有關(guān)的形狀信息。

toString方法的最大優(yōu)點(diǎn)是:如果調(diào)用了含有對(duì)象參數(shù)的println方法,則系統(tǒng)會(huì)自動(dòng)調(diào)用toString方法打印出相應(yīng)的信息。正因?yàn)槿绱?,一個(gè)類中常常將Object類的toString方法進(jìn)行覆蓋,并在toString方法的方法體中以字符串的方式返回要輸出的信息,然后在println方法中直接以對(duì)象名為參數(shù)輸出返回的字符串信息,如案例6-2的105行和109行println中的shapes[i]。6.3接口在Java語言中,組成程序的基本構(gòu)件有兩種:一種是前面介紹的類;另一種是本節(jié)要介紹的接口。如果在一個(gè)源程序(即擴(kuò)展名為.java的文件)中定義了多個(gè)類,則程序在編譯后,每一個(gè)類對(duì)應(yīng)地要生成一個(gè)字節(jié)代碼文件(即擴(kuò)展名為.class的文件)。接口在Java語言中是一種與類相似的構(gòu)件,一個(gè)接口在編譯后也要生成一個(gè)字節(jié)代碼文件,但接口中只包含常量和抽象方法的定義。下面介紹有關(guān)接口的知識(shí)。6.3.1接口的基本知識(shí)接口(interface)將抽象類的概念更深入了一層。從形式上看,一個(gè)接口可以當(dāng)作是一個(gè)“純”抽象類,即接口中的方法只規(guī)定了方法名、參數(shù)列表以及返回類型,不定義方法主體,并且所有方法默認(rèn)為是公共的和抽象的(相當(dāng)于用public和abstract修飾)。接口中也可以包含基本數(shù)據(jù)類型的數(shù)據(jù)成員,但它們都默認(rèn)為用public、static和final修飾,即均為常量。

1.接口的定義接口不同于類,因此不能用class關(guān)鍵字標(biāo)識(shí),定義一個(gè)接口要使用interface關(guān)鍵字。下面是定義一個(gè)接口的常用語法:[訪問權(quán)限]interface接口名稱{[public][static][final]類型名稱=常量值;[public][abstract]返回值類型方法名(參數(shù)列表);}接口的訪問權(quán)限(即interface前的修飾符)只有兩種:public和缺省狀態(tài)。如果沒有修飾符(即缺省狀態(tài)),則表示此接口的訪問只限于同一個(gè)包中的類。如果使用修飾符,則只能是public修飾符,表示此接口是公有的,可以被不同包中的類訪問。接口體中只包含方法聲明和常量定義。由于在默認(rèn)情況下接口中的方法是公共的和抽象的,因此接口中的數(shù)據(jù)都是常量。下面是一個(gè)簡(jiǎn)單的接口定義實(shí)例://程序名:Printable.javapublicinterfacePrintable{intMAX_LINE_OF_PAGE=40;intMAX_LINE_SIZE=80;voidprint();}該接口中定義了兩個(gè)整型常量和一個(gè)方法。注意1:根據(jù)Java語言命名規(guī)則,基本數(shù)據(jù)類型為常量(即staticfinal修飾)時(shí),常量名全部采用大寫字母(用下劃線分隔單個(gè)標(biāo)識(shí)符里的多個(gè)單詞)。注意2:?因?yàn)榻涌谥械臄?shù)據(jù)成員全是常量,所以在定義接口的時(shí)候必須給這些常量賦值,否則會(huì)產(chǎn)生編譯錯(cuò)誤。使用下列命令編譯該接口:javacPrintable.java編譯后,用JDK自帶的工具軟件javap對(duì)生成的字節(jié)代碼文件進(jìn)行反編譯。該命令的用法為:javapPrintable反編譯后的結(jié)果為:publicinterfacePrintable{publicstaticfinalintMAX_LINE_OF_PAGE;publicstaticfinalintMAX_LINE_SIZE;publicabstractvoidprint();}由此可知,即使定義接口時(shí)在方法前面不加public和abstract,編譯系統(tǒng)也會(huì)自動(dòng)加上這兩個(gè)修飾符,并在數(shù)據(jù)成員的前面自動(dòng)加public、static和final三個(gè)修飾符。因此,在定義一個(gè)接口時(shí),方法和數(shù)據(jù)成員一般不寫修飾符。接口與類一樣,可以通過繼承(extends)技術(shù)來產(chǎn)生新的接口,這與類的繼承類似,但一個(gè)子接口可以繼承多個(gè)父接口(而類的繼承只能是單繼承)。接口的繼承也使用關(guān)鍵詞extends,其格式如下:[訪問權(quán)限]interface子接口名稱extends父接口1,父接口2,…,父接口n{…}子接口將繼承父接口中定義的所有方法和常量。

2.使用接口的原因在實(shí)際軟件開發(fā)中,多個(gè)不相干的類如果存在相同的屬性和類似功能的方法,就可以將這些屬性和方法單獨(dú)組織起來,定義成一個(gè)單獨(dú)的程序模塊,這個(gè)模塊可以使用接口來定義。例如,在開發(fā)一個(gè)倉(cāng)庫(kù)管理系統(tǒng)時(shí),系統(tǒng)涉及到很多種物品類,如有汽車配件類、家用電氣類等,這些物品類都要具有打印出相關(guān)物品信息的功能,那么就可以定義一個(gè)如上的Printable接口,其中包含了打印輸出時(shí)每行的最大字符數(shù)MAX_LINE_SIZE(80個(gè)字符)和每頁(yè)最多打印的行數(shù)MAX_LINE_OF_PAGE(40行),還包含一個(gè)用于打印物品信息的print方法。由于不同的庫(kù)存物品要打印輸出的內(nèi)容差別很大,因此print方法中的操作內(nèi)容只能在具體類中定義。為什么不將Printable接口定義為一個(gè)抽象類呢?因?yàn)槿绻麑⒁粋€(gè)接口定義成抽象類,那么繼承該抽象類的子類與抽象的父類之間應(yīng)該有“特殊與一般”的關(guān)系,如6.2節(jié)介紹的Rectangle子類繼承了抽象類Shape,它們之間就存在著“特殊與一般”的關(guān)系,即“矩形是一種形狀”。而接口與實(shí)現(xiàn)該接口的類之間沒有這種關(guān)系,如我們不能說“汽車配件是一種打印”,這不符合客觀事實(shí)和人們的思維邏輯。接口中只定義了人們關(guān)心的功能,并不考慮這些功能是如何實(shí)現(xiàn)的以及哪些類要實(shí)現(xiàn)這些功能。如我們定義了一個(gè)如下的接口:publicinterfaceCanFly{voidfly();}實(shí)現(xiàn)了這個(gè)接口的類表示可以飛行。鳥能飛,所以鳥類可以實(shí)現(xiàn)這個(gè)接口,飛機(jī)也能飛,所以飛機(jī)可以實(shí)現(xiàn)這個(gè)接口,其它可飛的東西也可以實(shí)現(xiàn)這個(gè)接口。在實(shí)際軟件開發(fā)中,假如你是一個(gè)項(xiàng)目經(jīng)理,需要管理多個(gè)開發(fā)人員,如果你希望開發(fā)的某些類要具有某種功能,最簡(jiǎn)單的做法就是由你定義一個(gè)接口,然后指示開發(fā)人員在設(shè)計(jì)類時(shí)實(shí)現(xiàn)這個(gè)接口。因此,接口也定義了一種能力,實(shí)現(xiàn)了這個(gè)接口的類,可以說就具有了這個(gè)接口所規(guī)定的能力。Java系統(tǒng)類庫(kù)中標(biāo)準(zhǔn)接口的命名大都以able結(jié)尾(表示具有完成某功能的能力),比如Comparable、Cloneable、Runable等。在Comparable接口中就定義了一個(gè)名叫CompareTo的方法,所有實(shí)現(xiàn)了Comparable接口的類都可以使用該方法進(jìn)行兩個(gè)對(duì)象之間的比較??梢詫⒔涌诳偨Y(jié)為:接口定義了一個(gè)類對(duì)外提供服務(wù)的規(guī)范,一個(gè)類可以按照這種規(guī)范來實(shí)現(xiàn)規(guī)范中包含的功能,其它的類也可以按照這種規(guī)范來使用功能。

3.實(shí)現(xiàn)接口一個(gè)類可以實(shí)現(xiàn)一個(gè)或多個(gè)接口,實(shí)現(xiàn)接口的類要在implements關(guān)鍵詞后指出所實(shí)現(xiàn)接口的名稱。其語法如下:class類名implements接口名1,接口名2…{

類體}實(shí)現(xiàn)了接口的類,一般要重寫接口中的所有抽象方法,且方法名前要加public。下面是一個(gè)示例程序:01interfaceCanSwim{02voidswimming();03}0405interfaceCanRun{06voidrunning();07}0809classTurtleimplementsCanSwim,CanRun{10publicvoidswimming(){11System.out.println("Turtleisswimming.");12}1314publicvoidrunning(){15System.out.println("Turtleisrunning.");16}17}1819classFishimplementsCanSwim{20publicvoidswimming(){21System.out.println("Fishisswimming.");22}23}2425classTestInterface{26publicstaticvoidmain(String[]args){27 Turtlet=newTurtle();28 t.swimming();29 t.running();30 Fishf=newFish();31 f.swimming();32}33}該示例程序中定義了CanSwim和CanRun兩個(gè)接口,實(shí)現(xiàn)了CanSwim接口的類表示能游泳,實(shí)現(xiàn)了CanRun接口的類表示能跑,龜(Turtle)既能游泳又能跑,所以實(shí)現(xiàn)了CanSwim和CanRun兩個(gè)接口。一般的魚(Fish)只會(huì)游泳,所以只實(shí)現(xiàn)了CanSwim接口。在Fish類與Turtle類中,對(duì)所實(shí)現(xiàn)接口中聲明的方法進(jìn)行了具體的定義,并且方法一定要用public修飾,否則會(huì)出現(xiàn)編譯錯(cuò)誤。這是因?yàn)镴ava語言中規(guī)定,在類中實(shí)現(xiàn)接口中定義的方法時(shí),不能比接口中定義的方法有更低的訪問權(quán)限。接口中定義的方法都是公共的,所以這些方法在實(shí)現(xiàn)接口的類中定義時(shí),只能定義成公共的。注意:一個(gè)類只能有一個(gè)父類,但可以實(shí)現(xiàn)多個(gè)接口。如定義了一個(gè)動(dòng)物類:classAnimal{…}則龜(Turtle)類可以定義為:classTurtleextendsAnimalimplementsCanSwim,CanRun{…}即Turtle類繼承了Animal類,實(shí)現(xiàn)了CanSwim和CanRun兩個(gè)接口。注意:如果一個(gè)類中沒有實(shí)現(xiàn)接口中聲明的所有方法,則這個(gè)類只能定義為一個(gè)抽象類。為了簡(jiǎn)單起見,Java語言不支持多重繼承,即一個(gè)類不能有多個(gè)父類。如果在程序中確實(shí)要實(shí)現(xiàn)多重繼承的機(jī)制,可以借助于接口來實(shí)現(xiàn),因?yàn)橐粋€(gè)類可以實(shí)現(xiàn)多個(gè)接口,如上例中的Turtle類。初學(xué)者在程序中使用接口時(shí),應(yīng)注意以下問題:●避免接口中所有的方法都用publicabstract修飾?!癖苊饨涌谥兴械臄?shù)據(jù)成員都用publicstaticfinal修飾(即為常量)。●接口中的數(shù)據(jù)成員在定義時(shí)必須有初值?!裨陬愔袑?shí)現(xiàn)接口中定義的方法時(shí),必須用public修飾?!窠涌诤统橄箢愐粯?,都不能用來創(chuàng)建實(shí)例對(duì)象。由于接口中定義的數(shù)據(jù)成員都是靜態(tài)的和公共的常量,而靜態(tài)數(shù)據(jù)成員屬于類成員,因此在實(shí)現(xiàn)了接口的類中,可以直接以“接口名.常量名”的方式引用接口中定義的數(shù)據(jù)成員。6.3.2【案例6-3】可以飛行的類

1.案例描述定義具有可飛行特性的類。該案例的目的是為了說明接口在程序中的應(yīng)用和接口是如何實(shí)現(xiàn)多態(tài)性的。

2.案例效果案例程序的執(zhí)行效果如圖6-6所示。從圖中可以看出,鳥可以在空中飛行,飛機(jī)也可以在空中飛行。圖6-6案例6-3的執(zhí)行效果

3.技術(shù)分析飛行并不是某類所專有的特性,鳥可以飛行,飛機(jī)也可以飛行,而鳥和飛機(jī)是兩個(gè)互不相干的類,只不過它們都具有可飛行的特性。因此,可以定義一個(gè)具有“可飛行(Flyable)”功能的接口,在定義鳥類和飛機(jī)類時(shí)分別去實(shí)現(xiàn)“可飛行”這個(gè)接口。

4.程序解析案例程序如下:01//******************************************02//案例:6-303//程序名:TestFlyable.java04//功能:定義可以飛行的類05//******************************************0607interfaceFlyable{08 publicvoidfly();09}1011classBirdimplementsFlyable{12 publicvoidfly(){13 System.out.println("birdisflyingintheair.");14 }15}1617classPlaneimplementsFlyable{18 publicvoidfly(){19 System.out.println("planeisflyingintheair.");20 }21}2223classTestFlyable{24 staticvoidflying(Flyablef){25 f.fly();26 }27 28 publicstaticvoidmain(String[]args){29 Birdb=newBird();30 Planep=newPlane();31 flying(b);32 flying(p);33 }34}程序的07~09行定義了一個(gè)表示可飛行的接口Flyable,在可以飛行的接口中聲明了一個(gè)表示飛行的方法fly(),11~15行定義的Bird類實(shí)現(xiàn)了Flyable接口,17~21行定義的Plane類也實(shí)現(xiàn)了Flyable接口。在Bird類和Plane類中,都提供了對(duì)Flyable接口中fly()方法的具體實(shí)現(xiàn)。程序的23~34行定義了一個(gè)測(cè)試類TestFlyable,該類用于對(duì)可飛行的類進(jìn)行測(cè)試。在TestFlyable類中,定義了一個(gè)靜態(tài)的flying方法,該方法的參數(shù)是一個(gè)接口,調(diào)用該方法時(shí),實(shí)參應(yīng)為實(shí)現(xiàn)了Flyable接口的實(shí)例對(duì)象。由于不同的類可以實(shí)現(xiàn)相同的接口,因此flying方法的參數(shù)可以是不同類的對(duì)象。但由于這些不同類的對(duì)象都實(shí)現(xiàn)了相同的接口,因此它們都可以完成接口中定義的功能。故我們可以得出這樣的結(jié)論:當(dāng)用接口變量調(diào)用接口中聲明的方法時(shí),就通知相應(yīng)實(shí)現(xiàn)了接口的類的對(duì)象調(diào)用被類中所實(shí)現(xiàn)的那個(gè)方法。接口正是利用這個(gè)特點(diǎn)來實(shí)現(xiàn)多態(tài)性的。所以該程序中,在調(diào)用24行定義的flying方法時(shí),如果實(shí)參是一個(gè)鳥類的對(duì)象,則25行就表示調(diào)用鳥類中所實(shí)現(xiàn)的fly()方法,即表示鳥在空中飛翔;如果實(shí)參是一個(gè)飛機(jī)類的對(duì)象,則25行就表示調(diào)用飛機(jī)類中所實(shí)現(xiàn)的fly()方法,即表示飛機(jī)在空中飛翔。注意:與抽象類相似,在方法的參數(shù)列表中和變量的聲明中可用接口作數(shù)據(jù)類型,但這種類型的變量必須指向一個(gè)實(shí)現(xiàn)了該接口的類的實(shí)例對(duì)象。6.3.3【相關(guān)知識(shí)】抽象類與接口的比較抽象類和接口的有些特性是相似的,如:●抽象類和接口都不能用來實(shí)例化對(duì)象?!窨梢月暶鞒橄箢惡徒涌诘淖兞?,但對(duì)抽象類來說,要用抽象類的非抽象子類來實(shí)例化該變量;對(duì)接口來說,要用實(shí)現(xiàn)了該接口的非抽象子類來實(shí)例化該變量。●一個(gè)子類如果沒有實(shí)現(xiàn)抽象類中聲明的所有抽象方法,那么該子類也是一個(gè)抽象類;一個(gè)類如果沒有實(shí)現(xiàn)接口中聲明的所有方法,那么該類也是一個(gè)抽象類?!癯橄箢惡徒涌诙伎梢詫?shí)現(xiàn)程序的多態(tài)性。盡管抽象類和接口有些相似的特性,但它們?cè)诒举|(zhì)上是有很大區(qū)別的:●抽象類在Java語言中體現(xiàn)的是一個(gè)“父與子”的關(guān)系,即抽象類與子類之間必須存在“子類是父類中的一種”的關(guān)系,如抽象類“水果”與子類“蘋果”之間就存在“蘋果是一種水果”的關(guān)系。而接口與接口的實(shí)現(xiàn)者之間不必有“父與子”的關(guān)系,接口的實(shí)現(xiàn)者只是具有接口中定義的行為而已?!癯橄箢愔锌梢远x非抽象的方法,而接口中的所有方法都是抽象的。●接口中的數(shù)據(jù)成員只能是常量。●在抽象類中增加一個(gè)方法并賦予其默認(rèn)的行為(即增加一個(gè)非抽象的方法)時(shí),并不一定要修改子類,但如果接口被修改了,即增加或去掉了某個(gè)功能,則所有實(shí)現(xiàn)了該接口的類一定要重新修改。下面舉一個(gè)例子加以說明。比如說在一個(gè)簡(jiǎn)單的商品管理系統(tǒng)中,可以定義一個(gè)抽象的商品類:abstractclassGoods{protecteddoublecost;abstractpublicvoidsetCost(doublecost);abstractpublicdoublegetCost();}每種商品都有價(jià)格cost,都可以設(shè)置(setCost)與取得(getCost)商品的價(jià)格。有些商品有過期日期(如食品類商品),有些商品沒有過期日期(如文具等商品),對(duì)于有過期日期的商品,希望能在過期前的一定時(shí)間內(nèi)進(jìn)行過期通知。顯然,對(duì)于每種商品來說,并不是都具有過期這種行為,因此,可以將過期行為定義為一個(gè)接口:publicinterfaceExpiration{voidsetExpirationDate(Datedate);voidexpire();}其中,setExpirationDate方法用于設(shè)置過期日期,expire方法用于過期日期的通知。那么,對(duì)服裝類商品可以定義如下:classClothesextendsGoods{…}而將食品類可以定義為:classFoodextendsGoodsimplementsExpiration{…}6.4JAR文檔在安裝Java后,會(huì)在安裝目錄的lib文件夾中建立一些擴(kuò)展名為?.jar的文件。jar文件是Java中非常有用的一種文件格式,它的一種壓縮文件格式類似于Windows中常見的ZIP文件。用Java語言開發(fā)的應(yīng)用程序可以使用jar.exe工具(在JDK安裝目錄的bin文件夾中)壓縮后進(jìn)行發(fā)布;另外,為使用方便起見,用戶常用的一些類也可以壓縮成jar文件。6.4.1創(chuàng)建可執(zhí)行的JAR文件使用jar.exe工具可以將應(yīng)用程序及其涉及到的類壓縮成一個(gè)jar文件,然后可以使用Java程序的解釋器java.exe來執(zhí)行這個(gè)壓縮文件。當(dāng)然,在執(zhí)行jar文件時(shí)需要使用-jar參數(shù)。下面舉例說明創(chuàng)建一個(gè)可執(zhí)行jar文件的步驟:

(1)準(zhǔn)備要壓縮的字節(jié)代碼文件。如在D:\java目錄中定義了如下的A類(文件名為A.java):publicclassA{ publ

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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)論