《Java程序案例教程》課件第6章_第1頁
《Java程序案例教程》課件第6章_第2頁
《Java程序案例教程》課件第6章_第3頁
《Java程序案例教程》課件第6章_第4頁
《Java程序案例教程》課件第6章_第5頁
已閱讀5頁,還剩135頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第6章類的繼承6.1繼承的基本概念

6.2抽象類

6.3Object類

6.4final關(guān)鍵字

6.5接口(interface)

6.6對(duì)象的多態(tài)性

6.7匿名內(nèi)部類

6.1繼承的基本概念

現(xiàn)在假設(shè)有一個(gè)Person類,其中有name與age兩個(gè)屬性,而另外一個(gè)Student類,需要有name、age、school三個(gè)屬性,如圖6-1所示。從圖6-1中可以看出,Person中已經(jīng)存在有name和age兩個(gè)屬性,所以不希望在Student類中再重新聲明這兩個(gè)屬性,這時(shí)就需要考慮將Person類中的內(nèi)容繼續(xù)保留到Student類中。這就引出了類的繼承的概念。圖6-1Student類與Person類圖6-2Person與Student的繼承關(guān)系此處希望Student類能夠?qū)erson類的內(nèi)容繼承下來后繼續(xù)使用,如圖6-2所示。程序說明:

(1)第1~5行聲明一個(gè)名為Person的類,其中有name與age兩個(gè)屬性。

(2)第6~9行聲明一個(gè)名為Student的類,并繼承自Person類。

(3)第14行聲明并實(shí)例化一個(gè)Student類的對(duì)象。

(4)第16、18、20行分別用Student類的對(duì)象調(diào)用程序中的name、age、school屬性。

由上面的程序可以看出,在Student類中雖然并未定義name與age屬性,但在程序外部依然可以調(diào)用name或age,這是因?yàn)镾tudent類直接繼承自Person類。也就是說,Student類直接繼承了Person類中的屬性,所以Student類的對(duì)象才可以訪問到父類中的成員,如圖6-3所示。圖6-3Person與Student類的繼承圖在Java中只允許單繼承,而不允許多重繼承。也就是說,一個(gè)子類只能有一個(gè)父類,但是Java中卻允許多層繼承。

多重繼承示意圖如圖6-4所示。多重繼承語法如下:

由上面程序可以看出,類C同時(shí)繼承了類A與類B,也就是說,類C同時(shí)繼承了兩個(gè)父類,這在Java中是不允許的。圖6-4多重繼承圖6-5多層繼承示意圖6.1.1子類對(duì)象的實(shí)例化過程

既然子類可以繼承直接父類中的方法與屬性,那父類中的構(gòu)造方法呢?

【例6-2】TestPersonStudentDemo1.java。程序說明:

(1)第1~10行聲明一個(gè)Person類,此類中有一無參構(gòu)造方法。

(2)第11~19行聲明一個(gè)Student類,此類繼承自Person類,此類中也有一個(gè)無參構(gòu)造方法。

(3)第24行聲明并實(shí)例化一個(gè)Student類的對(duì)象s。

從程序的輸出結(jié)果可以看出,雖然程序第24行實(shí)例化的是子類的對(duì)象,但是程序先去調(diào)用父類中的無參構(gòu)造方法,之后再調(diào)用子類本身的構(gòu)造方法。所以由此可以得出結(jié)論,子類對(duì)象在實(shí)例化時(shí)會(huì)默認(rèn)先去調(diào)用父類中的無參構(gòu)造方法,之后再調(diào)用本類中的相應(yīng)構(gòu)造方法。實(shí)際上在本例中,在子類構(gòu)造方法的第一行默認(rèn)隱含了一個(gè)“super()”語句,上面的程序改寫成下面的形式也是可以的:在子類繼承父類的時(shí)候經(jīng)常會(huì)有下面的問題產(chǎn)生,例如:

【例6-3】TestPersonStudentDemo2.java。由編譯結(jié)果可以發(fā)現(xiàn),系統(tǒng)提供的出錯(cuò)信息是因?yàn)闊o法找到Person類,所以造成了編譯錯(cuò)誤,這是為什么呢?讀者可以發(fā)現(xiàn),在類Person中提供了一個(gè)有兩個(gè)參數(shù)的構(gòu)造方法,而并沒有明確寫出無參構(gòu)造方法。在本書前面已提到過,如果程序中指定了構(gòu)造方法,則默認(rèn)構(gòu)造方法不會(huì)再生成,本例即是如此。由于第24行實(shí)例化子類對(duì)象時(shí)找不到父類中的無參構(gòu)造方法,所以程序出現(xiàn)了錯(cuò)誤,而只要在Person類中增加一個(gè)什么都不做的構(gòu)造方法,這一問題就可以解決了。

【例6-4】TestPersonStudentDemo3.java。6.1.2super關(guān)鍵字的使用

在前面的程序中曾經(jīng)提到過super的使用,那么super到底是什么呢?從TestPersonStudentDemo1后面的更改程序中可以看出,super關(guān)鍵字出現(xiàn)在子類中,而且去調(diào)用了父類中的構(gòu)造方法,所以super的主要功能是完成子類調(diào)用父類中的內(nèi)容,也就是調(diào)用父類中的屬性或方法。將程序TestPersonStudentDemo3.java作相應(yīng)的修改就形成了TestPersonStudentDemo4.java。

【例6-5】TestPersonStudentDemo4.java。

(3)第16~20行聲明一個(gè)子類的構(gòu)造方法,此方法用super("張三",25)調(diào)用父類中有兩個(gè)參數(shù)的構(gòu)造方法。

(4)第26行聲明并實(shí)例化一個(gè)Student類的對(duì)象s。

(5)第28行為Student對(duì)象s中的school賦值為“北京”。

讀者可以發(fā)現(xiàn),本例與例6-4的程序基本上是一樣的,唯一的不同是在子類的構(gòu)造方法中明確指明了調(diào)用的是父類中有兩個(gè)參數(shù)的構(gòu)造方法,所以程序在編譯時(shí)不再去找父類中的無參構(gòu)造方法。用super調(diào)用父類中的構(gòu)造方法,只能放在程序的第一行。

super關(guān)鍵字不僅可以調(diào)用父類中的構(gòu)造方法,也可以調(diào)用父類中的屬性或方法,調(diào)用格式如下:

super.父類中的屬性;

super.父類中的方法();

【例6-6】TestPersonStudentDemo5.java。程序說明:

(1)第1~13行聲明一個(gè)名為Person的類,并聲明name與age兩個(gè)屬性、一個(gè)返回String類型的talk()方法,以及一個(gè)無參構(gòu)造方法。

(2)第14~28行聲明一個(gè)名為Student的類,此類直接繼承自Person類。

(3)第21、22行通過super屬性的方式調(diào)用父類中的name與age屬性,并分別賦值。

(4)第24行調(diào)用父類中的talk()方法并打印信息。

從上面的程序中可以看出,子類Student可以通過super調(diào)用父類中的屬性或方法。在本例中如果程序第21、22、24行換成this調(diào)用也是可以的,那為什么還要用super呢?6.1.3節(jié)將給出答案。6.1.3限制子類的訪問

有時(shí)父類并不希望子類可以訪問自己類中的全部屬性或方法,需要將一些屬性與方法隱藏起來,不讓子類去使用,所以在聲明屬性或方法時(shí)往往加上“private”關(guān)鍵字,表示私有。

【例6-7】TestPersonStudentDemo6.java。對(duì)于例6-7,讀者可能會(huì)有這樣的結(jié)論:只要父類中的屬性被“private”聲明,那么子類就再也無法訪問到它了。實(shí)際上并不是這樣的,在父類中加入了private關(guān)鍵字修飾,其目的只是相當(dāng)于對(duì)子類隱藏了此屬性,子類無法去顯式地調(diào)用這些屬性,但是可以隱式地去調(diào)用。下面的例子修改自例6-7。

【例6-8】TestPersonStudentDemo7.java。6.1.4復(fù)寫

“復(fù)寫”的概念與“重載”相似,它們均是Java“多態(tài)”的技術(shù)之一。所謂“重載”,指方法名稱相同,卻可在不同的場合做不同的事。當(dāng)一個(gè)子類繼承一父類,而子類中的方法與父類中的方法的名稱、參數(shù)個(gè)數(shù)、類型都完全一致時(shí),就稱子類中的這個(gè)方法復(fù)寫了父類中的方法。同理,如果子類中重復(fù)定義了父類中已有的屬性,則稱此子類中的屬性復(fù)寫了父類中的屬性。方法的復(fù)寫格式如下:程序說明:

(1)第1~9行聲明一個(gè)名為Person的類,其中聲明了name與age兩個(gè)屬性以及一個(gè)talk()方法。

(2)第11~25行聲明一個(gè)名為Student的類,此類繼承自Person類,也就繼承了name與age屬性,同時(shí)聲明了一個(gè)與父類中同名的talk()方法,也可以說此時(shí)Student類中的talk()方法復(fù)寫了Person類中的talk()方法。

(3)第30行實(shí)例化一個(gè)子類對(duì)象,并同時(shí)調(diào)用子類構(gòu)造方法為屬性賦初值。

(4)第32行用子類對(duì)象調(diào)用talk()方法,但此時(shí)調(diào)用的是子類中的talk()方法。由輸出結(jié)果可以看出,在子類中復(fù)寫了父類中的talk()方法,所以子類對(duì)象在調(diào)用talk()方法時(shí),實(shí)際上調(diào)用的是子類中被復(fù)寫好了的方法。另外可以看出,子類的talk()方法與父類的talk()方法在聲明權(quán)限時(shí)都聲明為public,也就是說這兩個(gè)方法的訪問權(quán)限都是一樣的。

子類復(fù)寫父類中的方法時(shí),被子類復(fù)寫的方法不能擁有比父類更嚴(yán)格的訪問權(quán)限(關(guān)于訪問權(quán)限的概念,后面會(huì)有更詳細(xì)介紹)。例如:程序說明:

(1)第1~9行聲明一個(gè)Person類,其中聲明了name與age兩個(gè)屬性,以及一個(gè)talk()方法。

(2)第10~25行聲明一個(gè)Student類,此類繼承自Person,也就繼承了name與age屬性,同時(shí)聲明了一個(gè)與父類中同名的talk()方法,也可以說此時(shí)Student類中的talk()方法復(fù)寫了Person類中的talk()方法,在第23行通過super.talk()方式調(diào)用父類中的talk()方法。

(3)第30行實(shí)例化一個(gè)子類對(duì)象,并同時(shí)調(diào)用子類構(gòu)造方法為屬性賦初值。

(4)第32行用子類對(duì)象調(diào)用talk()方法,但此時(shí)調(diào)用的是子類中的talk()方法。由上面程序可以看出,在子類中可以通過super()方法調(diào)用父類中被子類復(fù)寫的方法。

關(guān)于this與super關(guān)鍵字的使用,對(duì)于一些初學(xué)者來說可能容易混淆。表6-1對(duì)this與super的差別進(jìn)行了比較。表6-1this與super的比較案例1繼承案例

【案例描述】

編寫一個(gè)people類,該類的名字是age、hand和leg,訪問權(quán)限是友好的int型成員變量,可以輸出age、hand和leg三個(gè)變量值的protectedvoidshowPeopleMess()方法。編寫一個(gè)Student類,該類是People類的子類。Student類中聲明一個(gè)名字是number、訪問權(quán)限是友好的int型成員變量。Student類中定義一個(gè)輸出number的值的voidtellNumber()方法,以及計(jì)算兩個(gè)整數(shù)的和的intadd(intx,inty)方法。編寫一個(gè)UniverStudent類,該類是Student的子類。

【代碼與注釋】 6.2抽象類

通過繼承,可以從原有的類派生出新的類。原有的類稱為基類或父類,而新的類則稱為派生類或子類。通過這種機(jī)制派生出的新的類不僅可以保留原有的類的功能,而且還可以擁有更多功能。除了上述機(jī)制之外,Java也可以創(chuàng)建一種類專門用做父類,這種類稱為“抽象類”。抽象類的作用有點(diǎn)類似“模版”,其目的是要設(shè)計(jì)者依據(jù)它的格式來修改并創(chuàng)建新的類。但是并不能直接由抽象類創(chuàng)建對(duì)象,只能通過抽象類派生出新的類,再由它來創(chuàng)建對(duì)象。

抽象類的定義規(guī)則如下:

(1)抽象類和抽象方法都必須用abstract關(guān)鍵字來修飾。

(2)抽象類不能被實(shí)例化,也就是不能用new關(guān)鍵字去產(chǎn)生對(duì)象。

(3)抽象方法只需聲明,而不需實(shí)現(xiàn)。

(4)含有抽象方法的類必須被聲明為抽象類,抽象類的子類必須復(fù)寫所有的抽象方法后才能被實(shí)例化,否則這個(gè)子類還是一個(gè)抽象類。

抽象類的定義格式如下:在抽象類定義的語法中,方法的定義可分為兩種:一種是一般的方法,它和前面介紹過的方法一樣;另一種是“抽象方法”,它是以abstract關(guān)鍵字為開頭的方法,此方法只聲明了返回值的數(shù)據(jù)類型、方法名稱與所需的參數(shù),沒有定義方法體。

【例6-11】TestAbstractDemo1.java。

(2)第9~23行聲明一個(gè)Student類,此類繼承自Person類,而且此類不為抽象類,所以需要復(fù)寫Person類中的抽象方法talk()。

(3)第24~38行聲明一個(gè)Worker類,此類繼承自Person類,而且此類不為抽象類,所以需要復(fù)寫Person類中的抽象方法talk()。

(4)第43、44行分別實(shí)例化Student類與Worker類的對(duì)象,并調(diào)用各自的構(gòu)造方法初始化類屬性。

(5)第45、46行分別調(diào)用各自類中被復(fù)寫的talk()方法。

可以發(fā)現(xiàn),兩個(gè)子類Student、Worker都分別按各自的要求復(fù)寫了talk()方法。上面的程序可由圖6-6表示。圖6-6抽象類的繼承關(guān)系與一般類相同,在抽象類中,也可以擁有構(gòu)造方法,但是這些構(gòu)造方法必須在子類中被調(diào)用。例如: 6.3Object類

Java中有一個(gè)比較特殊的類—Object類,它是所有類的父類。如果一個(gè)類沒有使用extends關(guān)鍵字明確標(biāo)識(shí)繼承另外一個(gè)類,那么這個(gè)類就默認(rèn)繼承Object類。因此,Object類是Java類層中的最高層類,是所有類的超類。換句話說,Java中任何一個(gè)類都是它的子類。由于所有的類都是由Object類衍生出來的,所以O(shè)bject類中的方法適用于所有類。

例如:由JDK的幫助文檔可知,在Object類的方法中有一個(gè)toString()方法。

此方法是在打印對(duì)象時(shí)被調(diào)用的。下面有兩個(gè)例子,一個(gè)未復(fù)寫toString()方法,另一個(gè)復(fù)寫了toString()方法,讀者可比較兩者的區(qū)別。

【例6-12】TestToStringDemo1.java。程序說明:

(1)第1~5行聲明一個(gè)名為Person的類,并明確指出繼承自O(shè)bject類。

(2)第10行聲明并實(shí)例化一個(gè)Person類的對(duì)象p。

(3)第11行打印對(duì)象。

從上面的程序中可以看出,在打印對(duì)象p時(shí)實(shí)際上打印出的是一些無序的字符串。下面的例子復(fù)寫了Object類中的toString()方法。

【例6-13】TestToStringDemo2.java。 6.4final關(guān)鍵字

在Java中聲明類、屬性和方法時(shí),可使用關(guān)鍵字final來修飾。

(1)?final標(biāo)記的類不能被繼承。

(2)?final標(biāo)記的方法不能被子類復(fù)寫。

(3)?final標(biāo)記的變量(成員變量或局部變量)即為常量,只能賦值一次。

【例6-14】TestFinalDemo1.java。

6.5接口(interface)

接口(interface)是Java所提供的另一種重要技術(shù),它的結(jié)構(gòu)和抽象類非常相似,也具有數(shù)據(jù)成員與抽象方法,但它與抽象類又有以下兩點(diǎn)不同:

(1)接口中的數(shù)據(jù)成員必須初始化,且數(shù)據(jù)成員均為常量。

(2)接口中的方法必須全部聲明為abstract。也就是說,接口不能像抽象類一樣保有一般的方法,而必須全部是“抽象方法”。

接口定義的語法如下:接口與一般類一樣,本身也具有數(shù)據(jù)成員與方法,但數(shù)據(jù)成員一定要賦初值,且此值不能再更改,方法也必須是“抽象方法”。也正因?yàn)榉椒ū仨毷浅橄蠓椒ǎ鴽]有一般的方法,所以接口定義的語法中,抽象方法聲明的關(guān)鍵字abstract是可以省略的。相同的情況也發(fā)生在數(shù)據(jù)成員身上,因數(shù)據(jù)成員必須賦初值,且此值不能再被更改,所以聲明數(shù)據(jù)成員的關(guān)鍵字final也可省略。事實(shí)上,只要記得以下兩點(diǎn)即可:

(1)接口中的“抽象方法”只要做聲明即可,而不用定義其處理方式。

(2)數(shù)據(jù)成員必須賦初值。在Java中接口是用于實(shí)現(xiàn)多繼承的一種機(jī)制,也是Java設(shè)計(jì)中最重要的一個(gè)環(huán)節(jié),每個(gè)由接口實(shí)現(xiàn)的類必須在類內(nèi)部復(fù)寫接口中的抽象方法,且可自由地使用接口中的常量。

既然接口中只有抽象方法,那么它只要聲明而不用定義處理方式,于是自然可以聯(lián)想到接口也沒有辦法像一般類一樣,再用它來創(chuàng)建對(duì)象。利用接口打造新的類的過程稱為接口的實(shí)現(xiàn)(implementation)。

接口實(shí)現(xiàn)的語法如下:輸出結(jié)果:

學(xué)生->姓名:張三,年齡:25,職業(yè):學(xué)生!

程序說明:

(1)第1~8行聲明一個(gè)Person接口,在其中聲明了三個(gè)常量name、age、occupation,并分別賦值。

(2)第10~17行聲明一個(gè)Student類,此類實(shí)現(xiàn)Person接口,并復(fù)寫Person中的talk()方法。

(3)第22行實(shí)例化一個(gè)Student的對(duì)象s,并在第23行調(diào)用talk()方法,打印信息。接口是Java實(shí)現(xiàn)多繼承的一種機(jī)制,一個(gè)類只能繼承一個(gè)父類,但如果需要一個(gè)類繼承多個(gè)抽象方法,則明顯無法實(shí)現(xiàn),所以就出現(xiàn)了接口的概念。一個(gè)類只可以繼承一個(gè)父類,卻可以實(shí)現(xiàn)多個(gè)接口。接口與一般類一樣,均可通過擴(kuò)展技術(shù)來派生出新的接口。原來的接口稱為基本接口或父接口,派生出的接口稱為派生接口或子接口。通過這種機(jī)制,派生接口不僅可以保留父接口的成員,同時(shí)也可加入新的成員以滿足實(shí)際需要。同樣地,接口的擴(kuò)展(或繼承)也是通過關(guān)鍵字extends來實(shí)現(xiàn)的。有趣的是,一個(gè)接口可以繼承多個(gè)接口,這點(diǎn)與類的繼承有所不同。接口擴(kuò)展的語法如下:程序說明:

(1)第1~5行聲明一個(gè)接口A,并聲明一個(gè)常量i和一個(gè)抽象方法sayI()。

(2)第6~10行聲明一個(gè)接口E,并聲明一個(gè)常量x和一個(gè)抽象方法sayE()。

(3)第12~16行聲明一個(gè)接口B,此接口同時(shí)繼承A、E接口,同時(shí)聲明一個(gè)常量j和一個(gè)抽象方法sayJ()。

(4)第19~32行聲明一個(gè)類C,此類實(shí)現(xiàn)了B接口,所以此類中要復(fù)寫接口A、B、E中的全部抽象方法。

由上述程序可以看出,與類的繼承不同的是,一個(gè)接口可以同時(shí)繼承多個(gè)接口,也就是同時(shí)繼承了多個(gè)接口的抽象方法與常量。案例2接口案例

【案例描述】

定義接口Sound,該接口有voidmakeSound()方法;定義一個(gè)SoundMachine類,該類有一個(gè)voidplay(Soundsound)方法,即該方法的參數(shù)是接口類型。編寫幾個(gè)實(shí)現(xiàn)Sound接口的類。

【代碼與注釋】

6.6對(duì)象的多態(tài)性

什么叫多態(tài)性呢?重載的最終效果就是調(diào)用同一個(gè)方法名稱,卻可以根據(jù)傳入?yún)?shù)的不同而得到不同的處理結(jié)果,這其實(shí)就是多態(tài)性的一種體現(xiàn)。

下面用一個(gè)例子為讀者簡單介紹一下多態(tài)的概念。

【例6-19】

TestJavaDemo1.java。程序說明:

(1)第1~11行聲明一個(gè)Person類,此類中有fun1()、fun2()兩個(gè)方法。

(2)第13~24行聲明一個(gè)Student類,此類繼承自Person類,并復(fù)寫了fun1()方法。

(3)第30行聲明一個(gè)Person類(父類)的對(duì)象,之后由子類對(duì)象去實(shí)例化此對(duì)象。

(4)第32行由父類對(duì)象調(diào)用fun1()方法。

從程序的輸出結(jié)果可以看出,p是父類的對(duì)象,但調(diào)用fun1()方法時(shí)并沒有調(diào)用其本身的fun1()方法,而是調(diào)用了子類中被復(fù)寫了的fun1()方法。之所以會(huì)產(chǎn)生這樣的結(jié)果,最根本的原因就是父類對(duì)象并非由其本身的類實(shí)例化,而是通過子類實(shí)例化,這就是所謂的對(duì)象的多態(tài)性,即子類實(shí)例化對(duì)象可以轉(zhuǎn)換為父類實(shí)例化對(duì)象。

在這里要著重講解兩個(gè)概念,希望讀者加以重視。

(1)向上轉(zhuǎn)型。在上面TestJavaDemo1.java中,父類對(duì)象通過子類對(duì)象去實(shí)例化,實(shí)際上就是對(duì)象的向上轉(zhuǎn)型。向上轉(zhuǎn)型是不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換的,但是向上轉(zhuǎn)型會(huì)丟失精度。

(2)向下轉(zhuǎn)型。與向上轉(zhuǎn)型對(duì)應(yīng)的一個(gè)概念就是“向下轉(zhuǎn)型”。所謂向下轉(zhuǎn)型,也就是說父類的對(duì)象可以轉(zhuǎn)換為子類對(duì)象。但是需要注意的是,這時(shí)必須進(jìn)行強(qiáng)制的類型轉(zhuǎn)換。讀者可能覺得上面的兩個(gè)概念有些難以理解,下面舉例來幫助讀者理解:有個(gè)小孩在馬路上看見了一輛跑車,他指著跑車說那是汽車。相信讀者都認(rèn)為這句話沒有錯(cuò),跑車的確符合汽車的標(biāo)準(zhǔn),所以把跑車說成汽車并沒有錯(cuò)誤,只是不準(zhǔn)確而已。不管是小轎車也好,貨車也好,其實(shí)都是汽車,這在現(xiàn)實(shí)生活中是說得通的,在這里讀者可以將這些小轎車、貨車都想象成汽車的子類,它們都擴(kuò)展了汽車的功能,都具備了汽車的功能,所以它們都可以叫做汽車,那么這種概念就稱為向上轉(zhuǎn)型。相反地,假如說把所有的汽車都當(dāng)成跑車,那結(jié)果肯定是不正確的,因?yàn)槠囉泻芏喾N,必須明確指明是哪輛跑車才可以,需要加一些限制,這時(shí)就必須明確指明是哪輛車,所以需要進(jìn)行強(qiáng)制說明。上面的解釋可以概括成如下兩句話:

(1)向上轉(zhuǎn)型可以自動(dòng)完成。

(2)向下轉(zhuǎn)型必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

并非全部父類對(duì)象都可以強(qiáng)制轉(zhuǎn)換為子類對(duì)象。

【例6-20】

TestJavaDemo2.java。由上述程序可以看出,程序第32行Person對(duì)象p是由Person類本身實(shí)例化的,在第34行將Person對(duì)象p強(qiáng)制轉(zhuǎn)換為子類對(duì)象,這樣寫在語法上是沒有任何錯(cuò)誤的,但是在運(yùn)行時(shí)會(huì)發(fā)現(xiàn)出了異常,這是為什么呢?為什么父類不可以向子類轉(zhuǎn)換呢?其實(shí)這并不難理解,父類用其本身類實(shí)例化自己的對(duì)象,但它并不知道誰是自己的子類,那肯定在轉(zhuǎn)換的時(shí)候會(huì)出現(xiàn)錯(cuò)誤,那么這個(gè)錯(cuò)誤該如何糾正呢?只需要將第32行的代碼修改成如下形式即可:

Personp=newStudent();

這時(shí)相當(dāng)于由子類去實(shí)例化父類對(duì)象,也就是說,這時(shí)父類知道有這么一個(gè)子類,所以下面進(jìn)行轉(zhuǎn)換時(shí)就不會(huì)有問題了。6.6.1instanceof關(guān)鍵字的使用

可以用instanceof判斷一個(gè)類是否實(shí)現(xiàn)了某個(gè)接口,也可以用它來判斷一個(gè)實(shí)例對(duì)象是否屬于一個(gè)類。instanceof的語法格式如下:

對(duì)象instanceof類(或接口)

instanceof的返回值是布爾型的,或?yàn)檎?true),或?yàn)榧?false)。

【例6-21】

TestJavaDemo3.java。程序說明:

(1)第32行聲明一個(gè)父類對(duì)象p,并通過其子類實(shí)例化此對(duì)象。

(2)第32行用instanceof關(guān)鍵字判斷p對(duì)象是否是Student的實(shí)例。此例中,因?yàn)閜是通過Student類實(shí)例化的,所以此條件滿足。

(3)第35~36行將p對(duì)象強(qiáng)制轉(zhuǎn)換為Student類的對(duì)象,并調(diào)用fun1()方法。調(diào)用此方法時(shí),實(shí)際上調(diào)用的是被子類復(fù)寫了的fun1()方法。6.6.2復(fù)寫Object類中的equals方法

前面已經(jīng)介紹過Object是所有類的父類,其中的toString()方法是需要被復(fù)寫的,如果讀者去查JDK手冊,會(huì)發(fā)現(xiàn)在Object類中有一個(gè)equals方法,此方法用于比較對(duì)象是否相等,而且此方法必須被復(fù)寫。為什么要復(fù)寫該方法呢?請(qǐng)看下面的例子,下面的例子沒有復(fù)寫equals()方法。

【例6-22】TestOverEquals.java。由上面的程序可以看出,兩個(gè)對(duì)象的內(nèi)容完全相等,但為什么比較的結(jié)果不相等呢?因?yàn)閜1與p2的內(nèi)容分別在不同的內(nèi)存空間,指向了不同的內(nèi)存地址,所以在用equals比較時(shí),實(shí)際上是調(diào)用了Object類中的equals方法。但此方法并不好用,所以在開發(fā)中往往需要復(fù)寫equals方法。

【例6-23】TestOverEquals2.java。輸出結(jié)果:

是同一個(gè)人!

程序說明:

(1)第1~34行聲明一個(gè)Person類,并在類中復(fù)寫了Object類的equals方法。

(2)第15行聲明一個(gè)Person對(duì)象p1,并用this實(shí)例化。此時(shí),this就相當(dāng)于當(dāng)前調(diào)用此方法的對(duì)象,也就是第42行的t_p1對(duì)象。

(3)第17行判斷傳進(jìn)去的實(shí)例對(duì)象o是否屬于Person類的實(shí)例化對(duì)象,如果是則進(jìn)行轉(zhuǎn)型,否則返回false。

(4)第22行分別比較兩個(gè)對(duì)象的內(nèi)容是否相等,如果不相等,則返回false。

(5)第42行通過t_p1調(diào)用equals方法,并將t_p2對(duì)象的實(shí)例傳到equals方法之中,比較兩個(gè)對(duì)象是否相等。

6.6.3接口對(duì)象的實(shí)例化

接口是無法直接實(shí)例化的,因?yàn)榻涌谥袥]有構(gòu)造方法,但是可以根據(jù)對(duì)象多態(tài)性的概念,通過接口的子類對(duì)其進(jìn)行實(shí)例化。

【例6-24】TestInterfaceObject。輸出結(jié)果:

Studentfun1()

程序說明:

(1)第1~4行聲明一個(gè)Person接口,此接口中只有一個(gè)抽象方法fun1()。

(2)第5~11行聲明一個(gè)Student類,此類實(shí)現(xiàn)Person接口,并復(fù)寫fun1()方法。

(3)第16行聲明一個(gè)Person接口的對(duì)象p,并通過其子類Student類去實(shí)例化此對(duì)象。

(4)第17行調(diào)用fun1()方法,此時(shí)調(diào)用的是子類中復(fù)寫了的fun1()方法。從上面的程序中可以看出,接口是可以被實(shí)例化的,但是不能被直接實(shí)例化,只能通過其子類進(jìn)行實(shí)例化。在這里將Person聲明為

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(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)論