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

本章學(xué)習(xí)目標(biāo):第七章繼承與多態(tài)●

了解類與類之間的關(guān)系●

掌握繼承的概念和特點(diǎn)●

掌握方法的重寫(xiě)和應(yīng)用●

掌握super關(guān)鍵字和final關(guān)鍵字的應(yīng)用●

掌握多態(tài)向上轉(zhuǎn)型的應(yīng)用●

了解引用變量的強(qiáng)制類型轉(zhuǎn)換●

了解內(nèi)部類的概念、分類和

基本應(yīng)用第1節(jié)part類之間關(guān)系概述

在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,通常不會(huì)存在一個(gè)孤立的類,類和類之間總是存在一定的關(guān)系,通過(guò)這些關(guān)系,才能實(shí)現(xiàn)軟件的既定功能。掌握類與類之間的關(guān)系對(duì)于深入理解面向?qū)ο蟾拍罹哂蟹浅V匾淖饔?,也有利于程序員從專業(yè)的、合理的角度使用面向?qū)ο蠓治鰡?wèn)題和解決問(wèn)題。類之間關(guān)系概述類之間關(guān)系概述

根據(jù)UML(UnifiedModelingLanguage,統(tǒng)一建模語(yǔ)言)規(guī)范,類與類之間存在以下六種關(guān)系。

(1)繼承:一個(gè)類可以繼承另外一個(gè)類,并在此基礎(chǔ)上添加自己的特有功能。繼承也稱為泛化,表現(xiàn)的是一種共性與特性的關(guān)系。

(2)實(shí)現(xiàn):一個(gè)類實(shí)現(xiàn)接口中聲明的方法,其中接口對(duì)方法進(jìn)行聲明,而類完成方法的定義,即實(shí)現(xiàn)具體功能。實(shí)現(xiàn)是類與接口之間常用的關(guān)系,一個(gè)類可以實(shí)現(xiàn)一個(gè)或多個(gè)接口中的方法。

(3)依賴:在一個(gè)類的方法中操作另外一個(gè)類的對(duì)象,這種情況稱為第一個(gè)類依賴于第二個(gè)類。

(4)關(guān)聯(lián):在一個(gè)類中使用另外一個(gè)類的對(duì)象作為該類的成員變量,這種關(guān)系稱為關(guān)聯(lián)關(guān)系。關(guān)聯(lián)關(guān)系體現(xiàn)的是兩個(gè)類之間語(yǔ)義級(jí)別的一種強(qiáng)依賴關(guān)系。

(5)聚合:聚合關(guān)系是關(guān)聯(lián)關(guān)系的一種特例,體現(xiàn)的是整體與部分的關(guān)系,即has-a的關(guān)系。通常表現(xiàn)為一個(gè)類(整體)由多個(gè)其他類的對(duì)象(部分)作為該類的成員變量,此時(shí)整體與部分之間是可以分離的,整體和部分都可以具有各自的生命周期,部分可以屬于多個(gè)整體對(duì)象,與可以為多個(gè)整體對(duì)象共享。

(6)組成:組成關(guān)系也是關(guān)聯(lián)關(guān)系的一種特例,與聚合關(guān)系一樣也是體系整體與部分的關(guān)系,但組成關(guān)系中的整體與部分是不可分離的,即contains-a的關(guān)系,這種關(guān)系比聚合更強(qiáng),也稱為強(qiáng)聚合,當(dāng)整體的生命周期結(jié)束后,部分的生命周期也隨之結(jié)束。

類與類之間的這六種關(guān)系中,繼承和實(shí)現(xiàn)體現(xiàn)了類與類之間的一種縱向關(guān)系,而其余四種則體現(xiàn)了類與類之間的橫向關(guān)系。其中,關(guān)聯(lián)、聚合和組成這三種關(guān)系更多體現(xiàn)的是一種語(yǔ)義上的區(qū)別,而在代碼上則是無(wú)法區(qū)分的。類之間關(guān)系概述第2節(jié)part繼承

繼承是面向?qū)ο蟮娜筇卣髦?,也是?shí)現(xiàn)程序重復(fù)利用的重要手段。Java繼承具有單繼承的特點(diǎn),也就是每個(gè)子類只有一個(gè)直接父類。

類的繼承性類似與自然界中的繼承特性。例如,人類特征的遺傳,子女或多或少地體現(xiàn)了父母的特征。不過(guò)類的繼承子類除了具有父類原有的特性和功能之外,還可以增加一些新的特性和功能。例如,人類安裝工作性質(zhì)大致可以分為工、農(nóng)、兵、學(xué)、商等,但學(xué)生又可以根據(jù)學(xué)齡分為大、中、小學(xué)生,大學(xué)生又可以根據(jù)學(xué)校不同繼續(xù)細(xì)分,如圖7.1所示。繼承本節(jié)概述

從上圖可以看出,子類對(duì)象是一種特殊的父類對(duì)象,對(duì)對(duì)象(實(shí)例)進(jìn)行歸類時(shí),由于類型之間具有相似類似的特征,描述“某種東西是(或像)另外一種東西”這種關(guān)系時(shí),使用繼承性。7.2.1繼承的特點(diǎn)繼承的特點(diǎn)Java的繼承通過(guò)extends關(guān)鍵字來(lái)實(shí)現(xiàn),實(shí)現(xiàn)繼承的類被稱為子類,有的也稱其為派生類,被繼承的類被稱為父類,有的也稱其為基類或超類。父類和子類的關(guān)系,是一種一般和特殊的關(guān)系。例如水果和蘋果的關(guān)系,蘋果繼承了水果,蘋果是水果的子類,則蘋果是一種特殊的水果。Java里子類繼承父類的聲明格式如下;

【訪問(wèn)符】【修飾符】class子類名extends父類名{[屬性][方法]}7.2.1繼承的特點(diǎn)

其中,訪問(wèn)符、修飾符、class、子類名、大括號(hào)、屬性和方法與第六章類的定義完全相同,這里就不再贅述。Java使用extends作為繼承的關(guān)鍵字,extends關(guān)鍵字在英文中是擴(kuò)展,而不是繼承。這個(gè)關(guān)鍵字很好地體現(xiàn)了子類和父類的關(guān)系:子類是對(duì)父類的擴(kuò)展,子類是一種特殊的父類。

下述代碼示例了子類繼承父類的基本格式:publicclassSubClassextendsSuperClass{ ......}

上述代碼通過(guò)使用extends關(guān)鍵字使子類SubClass繼承了父類SuperClass。如果定義一個(gè)類沒(méi)有使用extends關(guān)鍵字繼承任何父類,則自動(dòng)繼承java.lang.Object類。Object類是所有類的頂級(jí)父類,在Java中,所有類都是直接或間接地繼承了Object類。

下述程序代碼示例了繼承的創(chuàng)建與繼承相應(yīng)的特點(diǎn),代碼如下:7.2.1繼承的特點(diǎn)【代碼7.1】Student.javapackagecom;//創(chuàng)建父類classPerson{ privateintage;//私有成員變量,年齡 Stringname;//默認(rèn)成員變量姓名 staticStringid;//靜態(tài)變量id編號(hào)

//聲明一個(gè)私有成員方法 privatevoidshowAge(){ System.out.println("年齡為:"+age); }

voidshowName(){ System.out.println("姓名為:"+name); }

//聲明一個(gè)靜態(tài)成員方法 publicstaticvoidshowId(){ System.out.println("id編號(hào)為:"+id); }}7.2.1繼承的特點(diǎn)//創(chuàng)建子類publicclassStudentextendsPerson{ Stringstuid;//學(xué)生證號(hào)

voiddisplay(){ System.out.println("姓名為:"+name+",id編號(hào)為:”+id+",學(xué)生證號(hào)為:"+stuid); } publicstaticvoidmain(String[]args){ Studentstu=newStudent(); //為屬性賦值

stu.age=20;//錯(cuò)誤,不能繼承父類私有成員變量 ="張三";//為姓名賦值 Student.id="001";//為靜態(tài)成員變量id編號(hào)賦值 stu.stuid="2018001";//為學(xué)生證號(hào)賦值 //調(diào)用方法

stu.showAge();//錯(cuò)誤,不能繼承父類私有成員方法 Student.showId(); stu.showName(); stu.display(); }}7.2.1繼承的特點(diǎn)

程序運(yùn)行結(jié)果如下:id編號(hào)為:001

姓名為:張三

姓名為:張三,id編號(hào)為:001,學(xué)生證號(hào)為:2018001

通過(guò)程序運(yùn)行結(jié)果可以發(fā)現(xiàn),Student類繼承了Person類,所以它具有Person類非私有的成員變量和方法,調(diào)用Person類的屬性和方法就像調(diào)用自己的屬性和方法一樣。7.2.1繼承的特點(diǎn)類的繼承性具有如下的特點(diǎn):(1)Java類繼承只支持單繼承。(2)子類能夠繼承父類的非私有成員變量和成員方法,包括類成員變量和類成員方法。(3)子類不能繼承父類的構(gòu)造方法。因?yàn)楦割悩?gòu)造方法創(chuàng)建的是父類對(duì)象,子類必須聲明自己的構(gòu)造方法,創(chuàng)建子類自己的對(duì)象。(4)創(chuàng)建子類對(duì)象時(shí),首先默認(rèn)要執(zhí)行父類不帶參數(shù)的構(gòu)造方法進(jìn)行初始化。(5)子類不能刪除從父類繼承過(guò)來(lái)的成員。(6)子類可以增加自己的成員變量和成員方法。(7)子類可以重寫(xiě)繼承自父類的成員變量和成員方法。(8)繼承具有傳遞性。7.2.1繼承的特點(diǎn)

在繼承過(guò)程中,子類擁有父類所定義的所有屬性和方法,但父類可以通過(guò)“封裝”思想隱藏某些數(shù)據(jù),只對(duì)子類提供可訪問(wèn)的屬性和方法。實(shí)例化一個(gè)子類對(duì)象時(shí),會(huì)先調(diào)用父類構(gòu)造方法進(jìn)行初始化,再調(diào)用子類自身的構(gòu)造方法進(jìn)行初始化,即構(gòu)造方法的執(zhí)行次序是父類→子類。

下述代碼示例了在繼承關(guān)系中父類和子類構(gòu)造方法的調(diào)用次序。7.2.1繼承的特點(diǎn)【代碼7.2】SubClass.javapackagecom;classSuperClass{ intnumber;//聲明一個(gè)屬性 publicSuperClass(){ this.number=1; System.out.println("調(diào)用父類不帶參數(shù)的構(gòu)造方法...number="+this.number); } publicSuperClass(intnumber){ this.number=number; System.out.println("調(diào)用父類帶參數(shù)的構(gòu)造方法...number="+this.number); }}7.2.1繼承的特點(diǎn)publicclassSubClassextendsSuperClass{ publicSubClass(){ this.number=20; System.out.println("調(diào)用子類不帶參數(shù)的構(gòu)造方法...number="+this.number); } publicSubClass(intnumber){ this.number=number; System.out.println("調(diào)用子類帶參數(shù)的構(gòu)造方法...number="+this.number); }

publicstaticvoidmain(String[]args){ SubClasss1=newSubClass(); System.out.println("s1.number="+s1.number); SubClasss2=newSubClass(15); System.out.println("s2.number="+s2.number); }}7.2.1繼承的特點(diǎn)

程序運(yùn)行結(jié)果如下:

調(diào)用父類不帶參數(shù)的構(gòu)造方法...number=1

調(diào)用子類不帶參數(shù)的構(gòu)造方法...number=20s1.number=20

調(diào)用父類不帶參數(shù)的構(gòu)造方法...number=1

調(diào)用子類帶參數(shù)的構(gòu)造方法...number=15s2.number=15

通過(guò)運(yùn)行結(jié)果可以發(fā)現(xiàn),在構(gòu)造一個(gè)子類對(duì)象時(shí),會(huì)首先調(diào)用父類不帶參數(shù)的構(gòu)造方法進(jìn)行初始化,而后再調(diào)用子類的構(gòu)造方法進(jìn)行初始化。在上述代碼中,如果注銷掉父類不帶參數(shù)的構(gòu)造構(gòu)造方法,會(huì)發(fā)現(xiàn)子類的兩個(gè)構(gòu)造方法都報(bào)錯(cuò);如果注銷掉父類帶參數(shù)的構(gòu)造方法,運(yùn)行結(jié)果完全一樣。7.2.2方法的重寫(xiě)方法的重寫(xiě)

子類繼承了父類,子類也是一個(gè)特殊的父類。大部分時(shí)候,子類總是以父類為基礎(chǔ),額外增加新的屬性和方法。但有一種情況例外,就是子類需要重寫(xiě)父類的方法。方法的重寫(xiě)也是多態(tài)的一種。例如,鳥(niǎo)類都包含了飛翔方法,其中有一種特殊的鳥(niǎo)不會(huì)飛翔,那就是鴕鳥(niǎo),因此它也將從鳥(niǎo)類繼承飛翔方法,但這個(gè)方法明顯不適合鴕鳥(niǎo),為此,鴕鳥(niǎo)需要重寫(xiě)鳥(niǎo)類的飛翔方法。

這種子類包含與父類同名方法的現(xiàn)象被稱為方法重寫(xiě),也被稱為方法覆蓋(Override)??梢哉f(shuō)子類重寫(xiě)了父類的方法,也可以說(shuō)子類覆蓋了父類的方法。下述代碼演示了鴕鳥(niǎo)對(duì)鳥(niǎo)類飛翔方法的重寫(xiě)。7.2.2方法的重寫(xiě)【代碼7.3】OverrideExample.javapackagecom;classBird{//定義Bird類的fly()方法publicvoidfly(){ System.out.println("我是鳥(niǎo)類,我能在天空自由自在地飛翔...");}}classOstrichextendsBird{//重寫(xiě)B(tài)ird類的fly()方法publicvoidfly(){ System.out.println("我雖然是鳥(niǎo)類,我卻不能在天空飛翔,我只可以在陸地上奔跑...");}}publicclassOverrideExample{publicstaticvoidmain(String[]args){ Ostrichos=newOstrich();//創(chuàng)建Ostrich的對(duì)象 os.fly();//執(zhí)行Ostrich對(duì)象的fly()方法}}7.2.2方法的重寫(xiě)

程序運(yùn)行結(jié)果如下:

我雖然是鳥(niǎo)類,我卻不能在天空飛翔,我只可以在陸地上奔跑...

執(zhí)行上面的程序可以看出,執(zhí)行os.fly()時(shí),執(zhí)行的不再是Bird類的fly()方法,而是執(zhí)行的Ostrich類的fly()方法。7.2.2方法的重寫(xiě)

方法的重寫(xiě)要遵循以下幾點(diǎn)原則:

(1)方法名、返回值類型、參數(shù)列表必須完全相同。

(2)子類方法聲明拋出的異常類應(yīng)該比父類方法聲明拋出的異常類更小或相等。

(3)子類方法的訪問(wèn)權(quán)限應(yīng)比父類方法的訪問(wèn)權(quán)限更大或相等。

(4)覆蓋方法和被覆蓋方法要么都是類方法,要么都是實(shí)例方法,不能一個(gè)是類方法一個(gè)是實(shí)例方法。例如,下述代碼將會(huì)引發(fā)編譯錯(cuò)誤。7.2.2方法的重寫(xiě)classFather{publicstaticdoubleadd(inta,intb){ returna+b;}}classSonextendsFather{publicdoubleadd(inta,intb){ returna+b;}}7.2.2方法的重寫(xiě)

當(dāng)子類覆蓋了父類方法后,子類的對(duì)象將無(wú)法訪問(wèn)父類中被覆蓋的方法,但可以在子類方法中調(diào)用父類中被覆蓋的方法。如果需要在子類方法中調(diào)用父類中被覆蓋的方法,則可以使用super(被覆蓋的是實(shí)例方法)關(guān)鍵字或者父類類名(被覆蓋的是類方法)作為調(diào)用者來(lái)調(diào)用父類中被覆蓋的方法。

如果父類方法具有private訪問(wèn)權(quán)限,則該方法對(duì)其子類是隱藏的,因此子類無(wú)法重寫(xiě)該方法。如果子類中定義了一個(gè)與父類private方法完全相同的方法,依然不是重寫(xiě),只是相當(dāng)于在子類中重新定義了一個(gè)新方法。例如下面代碼所示。7.2.2方法的重寫(xiě)classFather{privatedoubleadd(inta,intb){ returna+b;}}classSonextendsFather{//此處不是方法重寫(xiě),而是增加了一個(gè)新方法privatedoubleadd(inta,intb){ returna+b;}}

另外,父類方法和子類方法之間也可以發(fā)生方法重載現(xiàn)象,因?yàn)樽宇悤?huì)獲得父類方法,如果子類定義了一個(gè)與父類方法名相同而參數(shù)列表不同的方法,那么就形成了父類方法和子類方法的重載。7.2.3super關(guān)鍵字super關(guān)鍵字super是Java提供的一個(gè)關(guān)鍵字,super用于限定該對(duì)象調(diào)用它從父類繼承得到的屬性和方法。正如this一樣,super也不能出現(xiàn)在static修飾的方法中。super關(guān)鍵字代表父類對(duì)象,其主要用途有兩種。一種是在子類的構(gòu)造方法中調(diào)用父類的構(gòu)造方法;另一種是在子類方法中訪問(wèn)父類的屬性和方法。7.2.3super關(guān)鍵字1.調(diào)用父類構(gòu)造方法

在Java中,子類不能繼承父類的構(gòu)造方法,但子類構(gòu)造方法里可以通過(guò)super調(diào)用父類構(gòu)造方法,執(zhí)行父類構(gòu)造方法里的初始化代碼,類似于我們前面學(xué)習(xí)的this調(diào)用同類重載的構(gòu)造方法一樣。在一個(gè)構(gòu)造方法中調(diào)用另一個(gè)重載的構(gòu)造方法使用this調(diào)用來(lái)完成,在子類構(gòu)造器中調(diào)用父類構(gòu)造方法用super調(diào)用來(lái)完成。super關(guān)鍵字調(diào)用父類構(gòu)造方法的基本語(yǔ)法如下:super(參數(shù)列表);

其中,使用super調(diào)用父類構(gòu)造方法必須放在子類構(gòu)造方法方法體的第一行,所以this調(diào)用和super調(diào)用不會(huì)同時(shí)出現(xiàn)。參數(shù)列表里面參數(shù)初始化的屬性,必須是從父類繼承得到的屬性,而不是該類自己定義的屬性。下述代碼示例了super調(diào)用父類構(gòu)造方法的應(yīng)用,代碼如下所示。7.2.3super關(guān)鍵字【代碼7.4】StudentTwo.javapackagecom;classPerson{intage;//年齡Stringname;//姓名publicPerson(intage,Stringname){ this.age=age; =name;}}

publicclassStudentTwoextendsPerson{Stringstuid;//學(xué)生證號(hào)publicStudentTwo(intage,Stringname,Stringstuid){ super(age,name); this.stuid=stuid;}

7.2.3super關(guān)鍵字

voiddisplay(){ System.out.println("姓名為:"+name+",年齡為:" +age+",學(xué)生證號(hào)為:"+stuid);}

publicstaticvoidmain(String[]args){ StudentTwostu=newStudentTwo(20,"張三","001");stu.display();}}

程序運(yùn)行結(jié)果如下:

姓名為:張三,年齡為:20,學(xué)生證號(hào)為:001

從上面程序中可以看出,使用super調(diào)用和使用this調(diào)用很相似,區(qū)別只是在于super調(diào)用的是其父類的構(gòu)造方法,this調(diào)用的是同一個(gè)類中重載的構(gòu)造方法。7.2.3super關(guān)鍵字

不管我們是否使用super調(diào)用父類構(gòu)造方法,子類構(gòu)造方法總會(huì)調(diào)用父類構(gòu)造方法一次。子類調(diào)用父類構(gòu)造方法分如下幾種情況。

(1)子類構(gòu)造方法方法體第一行使用super顯示調(diào)用父類構(gòu)造方法,系統(tǒng)將根據(jù)super調(diào)用里傳入的實(shí)參列表調(diào)用父類對(duì)應(yīng)的構(gòu)造方法。

(2)子類構(gòu)造方法方法體的第一行代碼使用this顯示調(diào)用本類中重載的構(gòu)造方法,系統(tǒng)將根據(jù)this調(diào)用里傳入的實(shí)參列表調(diào)用本類中的另一個(gè)構(gòu)造方法。執(zhí)行本類中另一個(gè)構(gòu)造方法時(shí)即會(huì)調(diào)用父類構(gòu)造方法。

(3)子類構(gòu)造方法中既沒(méi)有super調(diào)用,也沒(méi)有this調(diào)用,系統(tǒng)將會(huì)在執(zhí)行子類構(gòu)造方法之前,隱式調(diào)用父類無(wú)參數(shù)的構(gòu)造方法。

不管上面哪種情況,當(dāng)調(diào)用子類構(gòu)造方法來(lái)初始化子類對(duì)象時(shí),父類構(gòu)造方法總會(huì)在子類構(gòu)造方法之前執(zhí)行。根據(jù)繼承的傳遞性可以推出,創(chuàng)建任何Java對(duì)象時(shí),最先執(zhí)行的總是java.lang.Object類的構(gòu)造方法。7.2.3super關(guān)鍵字2.調(diào)用父類的屬性和方法

當(dāng)子類定義的屬性與父類的屬性同名時(shí),這樣子類從父類繼承的這個(gè)屬性將被隱藏。如果需要使用父類被隱藏的屬性,可以使用“super.屬性名”格式來(lái)引用父類的屬性。當(dāng)子類重寫(xiě)了父類的方法時(shí),可以使用“super.方法名()”格式來(lái)調(diào)用父類的方法。

下述代碼示例了super關(guān)鍵字調(diào)用父類隱藏的屬性和重寫(xiě)的方法,代碼如下所示。7.2.3super關(guān)鍵字【代碼7.5】SuperExample.javapackagecom;classPerson{intage=30;//年齡staticStringname="張三";//姓名Stringid="001";//證件號(hào)碼

voiddisplay(){ System.out.println("調(diào)用父類中的display()方法。姓名為:"+name+",年齡為:"+age+",

證件號(hào)碼為:"+id); }}

7.2.3super關(guān)鍵字classStudentextendsPerson{intage=18;staticStringname="李四";//姓名

voiddisplay(){ System.out.println("調(diào)用子類中的display()方法。姓名為:"+name+",年齡為:"+age+",

證件號(hào)碼為:"+id); }

voidprint(){ System.out.println("父類中的年齡屬性為:"+super.age); System.out.println("父類中的姓名屬性為:"+P); System.out.println("子類中的年齡屬性為:"+age); System.out.println("子類中的姓名屬性為:"+name); super.display();//調(diào)用父類中的display()方法 display();//調(diào)用子類中的display()方法}}7.2.3super關(guān)鍵字publicclassSuperExample{publicstaticvoidmain(String[]args){ Studentstu=newStudent(); stu.print();}}程序運(yùn)行結(jié)果如下:父類中的年齡屬性為:30父類中的姓名屬性為:張三子類中的年齡屬性為:18子類中的姓名屬性為:李四調(diào)用父類中的display()方法。姓名為:張三,年齡為:30,證件號(hào)碼為:001調(diào)用子類中的display()方法。姓名為:李四,年齡為:18,證件號(hào)碼為:0017.2.3super關(guān)鍵字

從上面的程序可以看出,如果子類重寫(xiě)了父類的方法和隱藏了父類定義的屬性,如果需要調(diào)用父類被重寫(xiě)的方法和被隱藏的屬性,我們可以通過(guò)super關(guān)鍵字來(lái)實(shí)現(xiàn)。如果子類沒(méi)有隱藏父類的屬性,那么在子類實(shí)例中訪問(wèn)該屬性時(shí),則不須使用super關(guān)鍵字。如果在某個(gè)方法中訪問(wèn)名為a的屬性,則系統(tǒng)查找a的順序?yàn)椋?/p>

(1)查找該方法中是否有名為a的局部變量。

(2)查找當(dāng)前類中是否包含有名為a的屬性。

(3)查找該類的直接父類中是否包含有名為a的屬性,依次上溯到所有父類,直到j(luò)ava.lang.Object類,如果最終沒(méi)有找到該屬性,則系統(tǒng)出現(xiàn)編譯錯(cuò)誤。

當(dāng)程序創(chuàng)建一個(gè)子類對(duì)象時(shí),系統(tǒng)不僅會(huì)為該類中定義的實(shí)例變量分配內(nèi)存,也會(huì)為它從父類繼承得到的所有實(shí)例變量分配內(nèi)存,即使子類定義了與父類中同名的實(shí)例變量,都同樣分配內(nèi)存。例如,A類定義了2個(gè)屬性,B類定義了3個(gè)屬性,C類定義了2個(gè)屬性,并且A類繼承了B類,B類繼承了C類,那么創(chuàng)建A類對(duì)象時(shí),系統(tǒng)將會(huì)分配2+3+2個(gè)內(nèi)存空間給實(shí)例變量。7.2.4final關(guān)鍵字final關(guān)鍵字final關(guān)鍵字表示“不可改變的,最終的”的意思,可用于修飾類、變量和方法。當(dāng)final關(guān)鍵字修飾變量時(shí),表示該變量一旦被初始化,就不可被改變的量,即常量;當(dāng)final關(guān)鍵字修飾方法時(shí),表示該方法不可被子類重寫(xiě),即最終方法;當(dāng)final關(guān)鍵字修飾類時(shí),表示該類不可被子類繼承,即最終類。7.2.4final關(guān)鍵字1.final成員變量

在Java語(yǔ)法中規(guī)定,final修飾的成員變量必須由程序員顯示地指定初始值。final修飾的類成員變量和實(shí)例成員變量能指定初始值的地方如下:

(1)類成員變量必須在靜態(tài)初始化塊中或聲明該變量時(shí)指定初始值。

(2)實(shí)例成員變量必須在非靜態(tài)初始化塊、聲明該變量時(shí)或構(gòu)造方法中指定初始值。

下述代碼示例了final修飾的成員變量的各種具體情況。代碼如下所示。7.2.4final關(guān)鍵字【代碼7.6】FinalVariableExample.javapackagecom;publicclassFinalVariableExample{finalinta=10;//定義final成員變量時(shí)初始化值finalstaticdoubleb=9.8;//定義final類成員變量時(shí)初始化值finalStringstr;finalcharc;finalstaticbyted;//在非靜態(tài)塊中為final成員變量賦初始值{ c='a';}//在靜態(tài)塊中為final成員變量賦初始值static{ d='r';}//在構(gòu)造方法中為final成員變量賦初始值publicFinalVariableExample(){ str="String";}7.2.4final關(guān)鍵字publicstaticvoidmain(String[]args){ FinalVariableExamplefve=newFinalVariableExample(); System.out.println("a的值為:"+fve.a); System.out.println("b的值為:"+FinalVariableExample.b); System.out.println("c的值為:"+fve.c); System.out.println("d的值為:"+FinalVariableExample.d); System.out.println("str的值為:"+fve.str);}}

程序運(yùn)行結(jié)果如下:a的值為:10b的值為:9.8c的值為:ad的值為:114str的值為:String

與普通成員變量不同的是,final成員變量必須由程序員顯示初始化,系統(tǒng)不會(huì)對(duì)final成員變量進(jìn)行隱式初始化。7.2.4final關(guān)鍵字2.final方法

使用final修飾的方法不能被子類重寫(xiě)。如果某些方法完成了關(guān)鍵性的、基礎(chǔ)性的功能,不需要或不允許被子類改變,則可以將這些方法聲明為final的。下述代碼示例了final修飾的方法不能被重寫(xiě)。代碼如下所示。【代碼7.7】FinalMethodExample.javapackagecom;classFinalMethod{publicfinalvoidmethod(){ System.out.println(“final修飾的方法不能被重寫(xiě),可以被繼承");}}

classFinalMethodExampleextendsFinalMethod{

publicfinalvoidmethod(){}//錯(cuò)誤,final方法不能被重寫(xiě)publicstaticvoidmain(String[]args){ FinalMethodExamplefme=newFinalMethodExample(); fme.method();}}注銷掉報(bào)錯(cuò)代碼,程序運(yùn)行結(jié)果如下:final修飾的方法不能被重寫(xiě),可以被繼承7.2.4final關(guān)鍵字3.final類

使用final修飾的類不能被繼承。例如下述代碼所示:finalclassFather{}classSonextendsFather{//錯(cuò)誤,final類不能被繼承}

一個(gè)final類中的所有方法都被默認(rèn)為final的,因此final類中的方法不必顯示聲明為final。其實(shí),Java基礎(chǔ)類庫(kù)中的類都是final類,如String、Integer等,都無(wú)法被子類繼承。第3節(jié)part多態(tài)

多態(tài)性一般發(fā)生在子類和父類之間,就是同一種事物,由于條件不同,產(chǎn)生了不同的結(jié)果。多態(tài)性分為靜態(tài)性多態(tài)和動(dòng)態(tài)性多態(tài)。前面接觸到的方法的重載和重寫(xiě)就是靜態(tài)性多態(tài)。本節(jié)主要介紹的是動(dòng)態(tài)性多態(tài)。Java引用變量有兩個(gè)類型:一個(gè)是編譯的類型,一個(gè)是運(yùn)行時(shí)類型。編譯時(shí)類型由聲明變量時(shí)使用的類型決定,運(yùn)行時(shí)類型由實(shí)際賦給該變量的對(duì)象決定。如果編譯時(shí)類型和運(yùn)行時(shí)類型不一致,則稱為動(dòng)態(tài)性多態(tài)。多態(tài)本節(jié)概述7.3.1上轉(zhuǎn)型對(duì)象上轉(zhuǎn)型對(duì)象

所謂上轉(zhuǎn)型對(duì)象就是一個(gè)父類類型的引用變量可以指向其子類的對(duì)象,即將子類對(duì)象賦給一個(gè)父類類型的引用變量。

上轉(zhuǎn)型對(duì)象能夠訪問(wèn)到父類所有成員變量和父類中沒(méi)有被子類重寫(xiě)的方法,還可以訪問(wèn)到子類重寫(xiě)父類的方法,而不能訪問(wèn)到子類新增加的成員變量和方法。下述代碼示例了上轉(zhuǎn)型對(duì)象的訪問(wèn)特性,代碼所示如下。7.3.1上轉(zhuǎn)型對(duì)象【代碼7.8】PolymorphismExample.javapackagecom;classBaseClass{ inta=6;

publicvoidbase(){ System.out.println("父類的普通方法"); }

publicvoidtest(){ System.out.println("父類將被子類重寫(xiě)的方法"); }}

7.3.1上轉(zhuǎn)型對(duì)象publicclassPolymorphismExampleextendsBaseClass{ inta=20;//重新定義一個(gè)實(shí)例變量a,隱藏父類的實(shí)例變量 intb=10;

publicvoidtest(){ System.out.println("子類重寫(xiě)父類的方法"); }

publicvoidsub(){ System.out.println("子類新增的普通方法"); }

7.3.1上轉(zhuǎn)型對(duì)象 publicstaticvoidmain(String[]args){ //編譯時(shí)類型和運(yùn)行時(shí)類型完全一致,不存在多態(tài) BaseClassbc=newBaseClass(); System.out.println("bc.a="+bc.a); bc.base(); bc.test(); PolymorphismExamplesc=newPolymorphismExample(); System.out.println("sc.a="+sc.a); sc.base(); sc.test(); //編譯時(shí)類型和運(yùn)行時(shí)類型不一致,多態(tài)性發(fā)生 BaseClassbsc=newPolymorphismExample(); System.out.println("bsc.a="+bsc.a); bsc.base(); bsc.test(); //下面兩行代碼錯(cuò)誤,原因是運(yùn)行時(shí)多態(tài)不能調(diào)用子類新增的屬性和方法 //bsc.sub(); //System.out.println(bsc.b); }}程序運(yùn)行結(jié)果如下:bc.a=6父類的普通方法父類將被子類重寫(xiě)的方法sc.a=20父類的普通方法子類重寫(xiě)父類的方法bsc.a=6父類的普通方法子類重寫(xiě)父類的方法7.3.2引用變量的強(qiáng)制類型轉(zhuǎn)換引用變量的強(qiáng)制類型轉(zhuǎn)換

編寫(xiě)Java程序時(shí),引用變量只能調(diào)用它編譯時(shí)類型的方法,而不能調(diào)用它運(yùn)行時(shí)類型的方法,即使它實(shí)際所引用的對(duì)象確實(shí)包含該方法。如果需要讓這個(gè)引用變量調(diào)用它運(yùn)行時(shí)類型的方法,則必須把它強(qiáng)制轉(zhuǎn)換成運(yùn)行時(shí)類型,強(qiáng)制類型轉(zhuǎn)換需要借助類型轉(zhuǎn)換運(yùn)算符。

類型轉(zhuǎn)換運(yùn)算符是一對(duì)小括號(hào),類型轉(zhuǎn)換運(yùn)算符的用法是:(type)variable,這種用法可以將variable變量轉(zhuǎn)換成一個(gè)type類型的變量。這種強(qiáng)制類型轉(zhuǎn)換不是萬(wàn)能的,當(dāng)進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí)需要注意:

(1)基本類型之間的轉(zhuǎn)換只能在數(shù)值類型之間進(jìn)行,這里所說(shuō)的數(shù)值類型包括整數(shù)型、字符型和浮點(diǎn)型。但數(shù)值類型和布爾類型之間不能進(jìn)行類型轉(zhuǎn)換。

(2)引用類型之間的轉(zhuǎn)換只能在具有繼承關(guān)系的兩個(gè)類型之間進(jìn)行,如果是兩個(gè)沒(méi)有任何繼承關(guān)系的類型,則無(wú)法進(jìn)行類型轉(zhuǎn)換,否則編譯時(shí)就會(huì)出現(xiàn)錯(cuò)誤。如果試圖把一個(gè)父類實(shí)例轉(zhuǎn)換成子類類型,則這個(gè)對(duì)象必須實(shí)際上是子類實(shí)例才行(即編譯時(shí)類型是父類類型,而運(yùn)行時(shí)類型是子類類型),否則將會(huì)運(yùn)行時(shí)引發(fā)ClassCastException異常。

下述代碼示例了引用變量強(qiáng)制類型的轉(zhuǎn)換,代碼所示如下。7.3.2引用變量的強(qiáng)制類型轉(zhuǎn)換【代碼7.9】SchoolStudent.javapackagecom;classStudent{ Stringname="張三"; intage=20;

publicvoidstudy(){ System.out.println("學(xué)生就要好好學(xué)習(xí),天天向上"); }}

publicclassSchoolStudentextendsStudent{ Stringschool="重慶大學(xué)";

publicvoidmajor(){ System.out.println("我的專業(yè)是計(jì)算機(jī)軟件技術(shù)"); }7.3.2引用變量的強(qiáng)制類型轉(zhuǎn)換 publicstaticvoidmain(String[]args){ Studentstu=newSchoolStudent(); if(stuinstanceofSchoolStudent){ SchoolStudentstu2=(SchoolStudent)stu; System.out.println("姓名為:"++",年齡為:"+stu2.age +",學(xué)校為:"+stu2.school); stu2.major(); stu2.study(); } }}程序運(yùn)行結(jié)果如下:姓名為:張三,年齡為:20,學(xué)校為:重慶大學(xué)我的專業(yè)是計(jì)算機(jī)軟件技術(shù)學(xué)生就要好好學(xué)習(xí),天天向上

考慮到進(jìn)行強(qiáng)制類型轉(zhuǎn)換時(shí),可能會(huì)出現(xiàn)異常,因此進(jìn)行引用變量強(qiáng)制類型轉(zhuǎn)換之前先通過(guò)instanceof運(yùn)算符來(lái)判斷是否可以成功轉(zhuǎn)換,從而避免出現(xiàn)ClassCastException異常,這樣可以保證程序更加健壯。7.3.3instanceof運(yùn)算符instanceof運(yùn)算符instanceof運(yùn)算符是一個(gè)二目運(yùn)算符,左邊操作數(shù)通常是一個(gè)引用類型的變量,右邊操作數(shù)通常是一個(gè)類(也可以是接口),它用于判斷左邊的對(duì)象是否是后面的類,或者其子類、實(shí)例類的實(shí)例。如果是,則返回true,否則返回false。

在使用instanceof運(yùn)算符時(shí)需要注意:instanceof運(yùn)算符左邊操作數(shù)的編譯時(shí)類型要么與右邊的類相同,要么具有父子繼承關(guān)系,否則會(huì)引起編譯錯(cuò)誤。下述代碼示例了instanceof運(yùn)算符的用法,代碼示例如下。7.3.3instanceof運(yùn)算符【代碼7.10】InstanceofExample.javapackagecom;publicclassInstanceofExample{ publicstaticvoidmain(String[]args){ Objecthello="hello"; System.out.println("字符串是否是Object類的實(shí)例:"+(helloinstanceofObject)); System.out.println("字符串是否是String類的實(shí)例:"+(helloinstanceofString)); System.out.println("字符串是否是Math類的實(shí)例:"+(helloinstanceofMath)); System.out.println("字符串是否是Comparable接口的實(shí)例:" +(helloinstanceofComparable)); Stringstr="Hello"; //下面代碼編譯錯(cuò)誤 System.out.println("字符串是否是Math類的實(shí)例:"+(strinstanceofMath)); }}注銷錯(cuò)誤代碼,程序運(yùn)行結(jié)果如下:字符串是否是Object類的實(shí)例:true字符串是否是String類的實(shí)例:false字符串是否是Math類的實(shí)例:false字符串是否是Comparable接口的實(shí)例:true7.3.3instanceof運(yùn)算符

上述程序通過(guò)定義Objecthello="hello",這個(gè)變量的編譯時(shí)類型是Object類,但實(shí)際類型是String類。因?yàn)镺bject類是所有類、接口的父類,因此可執(zhí)行helloinstanceofMath和helloinstanceofComparable等。但如果使用Stringstr="Hello"代碼定義的str變量,就不能執(zhí)行strinstanceofMath,因?yàn)閟tr的編譯時(shí)類型是String類,而String類既不是Math類型,也不是Math類型的父類,所以這行代碼編譯就會(huì)出錯(cuò)。instanceof運(yùn)算符的作用是在進(jìn)行引用變量強(qiáng)制類型轉(zhuǎn)換之前,首先判斷前一個(gè)對(duì)象是否是后一個(gè)類的實(shí)例,是否可以轉(zhuǎn)換成功,從而保證代碼的健壯性。instanceof和(type)variable是Java提供的兩個(gè)相關(guān)的運(yùn)算符,通常先用instanceof判斷一個(gè)對(duì)象是否可以強(qiáng)制類型轉(zhuǎn)換,然后再使用(type)variable運(yùn)算符進(jìn)行強(qiáng)制類型轉(zhuǎn)換,從而保證程序不會(huì)出現(xiàn)錯(cuò)誤。第4節(jié)part內(nèi)部類Java語(yǔ)法中,允許在一個(gè)類的類體之內(nèi)再定義一個(gè)類,這個(gè)定義在其他類內(nèi)部的類就被稱為內(nèi)部類(或嵌套類),包含內(nèi)部類的類也被稱為外部類(或宿主類)。內(nèi)部類主要有如下作用。

(1)內(nèi)部類提供了更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個(gè)包的其他類訪問(wèn)該類。

(2)內(nèi)部類成員可以直接訪問(wèn)外部類的私有數(shù)據(jù),因?yàn)閮?nèi)部類被當(dāng)成外部類成員,同一個(gè)類的成員之間可以互相訪問(wèn)。但外部類不能訪問(wèn)內(nèi)部類的成員。

(3)匿名內(nèi)部類適合用于創(chuàng)建那些僅需要一次使用的類。Java內(nèi)部類主要分為非靜態(tài)內(nèi)部類、局部?jī)?nèi)部類、靜態(tài)內(nèi)部類和匿名內(nèi)部類四種。內(nèi)部類本節(jié)概述7.4.1非靜態(tài)內(nèi)部類

定義內(nèi)部類非常簡(jiǎn)單,只要把一個(gè)類放在另一個(gè)類內(nèi)部定義即可。此處的“類內(nèi)部”包括類中的任何位置,甚至在方法中也可以定義內(nèi)部類(局部?jī)?nèi)部類)。

大部分時(shí)候,內(nèi)部類都被作為成員內(nèi)部類定義,而不是作為局部?jī)?nèi)部類。成員內(nèi)部類是一種與屬性、成員方法、構(gòu)造方法和初始化語(yǔ)句塊相似的類成員。局部?jī)?nèi)部類和匿名內(nèi)部類則不是類成員。成員內(nèi)部類分為靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類兩種,使用static修飾的成員內(nèi)部類是靜態(tài)內(nèi)部類,沒(méi)有使用static修飾的成員內(nèi)部類是非靜態(tài)成員內(nèi)部類。由于內(nèi)部類作為其外部類的成員,所以可以使用任意訪問(wèn)權(quán)限控制符如private、protected和public等修飾。

下述代碼示例了非靜態(tài)內(nèi)部類的定義和使用,代碼如下所示。非靜態(tài)內(nèi)部類7.4.1非靜態(tài)內(nèi)部類【代碼7.11】InnerClassExample1.javapackageinner;importinner.Cow.CowLeg;classCow{ //外部類屬性 privatedoubleweight; //外部類構(gòu)造方法 publicCow(){ }

publicCow(doubleweight){ this.weight=weight; }

7.4.1非靜態(tài)內(nèi)部類 //定義非靜態(tài)內(nèi)部類 classCowLeg{ //內(nèi)部類屬性 privatedoubleheight; privateStringcolor; //內(nèi)部類構(gòu)造方法 publicCowLeg(){ } publicCowLeg(doubleheight,Stringcolor){ this.height=height; this.color=color; } //內(nèi)部類成員方法 publicdoublegetHeight(){ returnheight; } publicvoidsetHeight(doubleheight){ this.height=height; }

7.4.1非靜態(tài)內(nèi)部類 publicStringgetColor(){ returncolor; } publicvoidsetColor(Stringcolor){ this.color=color; } publicvoidprint(){ System.out.println("牛腿顏色是:"+this.color+",高為:"+this.height); //直接訪問(wèn)外部類的私有成員變量 System.out.println("奶牛重量為:"+weight); } } //外部類成員方法,訪問(wèn)內(nèi)部類 publicvoiddisplay(){ CowLegc1=newCowLeg(1.2,"黑白花"); c1.print(); }}

7.4.1非靜態(tài)內(nèi)部類publicclassInnerClassExample1{ publicstaticvoidmain(String[]args){ Cowcow=newCow(500); cow.display(); //同一個(gè)包中的類直接調(diào)用public和默認(rèn)修飾符的內(nèi)部類,必須用import導(dǎo)入 CowLegc1=cow.newCowLeg(1.2,"黑白花"); c1.print(); }}

上述代碼中,在Cow類中定義了一個(gè)默認(rèn)修飾符的CowLeg內(nèi)部類,并在CowLeg類的方法中直接訪問(wèn)了Cow類的私有屬性。在InnerClassExample1類的main()方法中,通過(guò)兩種方式訪問(wèn)了內(nèi)部類,一種是直接通過(guò)外部類的方法訪問(wèn)內(nèi)部類,這種方式適合所有修飾符的內(nèi)部類;另一種是通過(guò)外部類對(duì)象訪問(wèn)內(nèi)部類,需要用import導(dǎo)入內(nèi)部類路徑,也要受到內(nèi)部類訪問(wèn)權(quán)限修飾符的限制。程序運(yùn)行結(jié)果如下:

牛腿顏色是:黑白花,高為:1.2

奶牛重量為:500.0

牛腿顏色是:黑白花,高為:1.2

奶牛重量為:500.0

上述代碼編譯后,會(huì)生成三個(gè)class文件:兩個(gè)是外部類的class文件Cow.class和InnerClassExample1.class,另一個(gè)是內(nèi)部類的class文件Cow$CowLeg.class。內(nèi)部類的class文件形式都是“外部類名$內(nèi)部類名.class”。7.4.2局部?jī)?nèi)部類

在方法中定義的內(nèi)部類稱為局部?jī)?nèi)部類。與局部變量類似,局部?jī)?nèi)部類不能用public、private等訪問(wèn)修飾符和static修飾符進(jìn)行聲明,它的作用域被限定在聲明該類的方法塊中。局部?jī)?nèi)部類的優(yōu)勢(shì)在于:它可以對(duì)外界完全隱藏起來(lái),除了所在的方法之外,對(duì)其他方法而言是不透明的。此外與其他內(nèi)部類比較,局部?jī)?nèi)部類不僅可以訪問(wèn)包含它的外部類的成員,還可以訪問(wèn)局部變量,但這些局部變量必須被聲明為final。如果需要用局部?jī)?nèi)部類定義變量、創(chuàng)建實(shí)例或派生子類,那么都只能在局部?jī)?nèi)部類所在的方法內(nèi)進(jìn)行。

下述代碼示例了一個(gè)局部?jī)?nèi)部類的定義和使用,代碼如下所示。局部?jī)?nèi)部類7.4.2局部?jī)?nèi)部類【代碼7.12】localInnerClassExample.javapackageinner;publicclasslocalInnerClassExample{inta=10;publicvoidprint(){ System.out.println("外部類的方法");}publicvoidCreateInnerClassMethod(){ finalintb=20;//局部?jī)?nèi)部類訪問(wèn)的局部變量必須為final修飾符的 classLocalInnerClass{ intc=30; voidinnerPrint(){ System.out.println("局部?jī)?nèi)部類的方法"); } }

7.4.2局部?jī)?nèi)部類 classSubLocalInnerClassextendsLocalInnerClass{ intd=40; voiddisplay(){ print(); innerPrint(); System.out.println("局部?jī)?nèi)部類子類的方法"); System.out.println("a="+a+",b="+b+",c="+c+",d="+d); } } SubLocalInnerClasssic=newSubLocalInnerClass(); sic.display();}publicstaticvoidmain(String[]args){ localInnerClassExamplelocal=newlocalInnerClassExample(); local.CreateInnerClassMethod();}}7.4.2局部?jī)?nèi)部類

程序運(yùn)行結(jié)果如下:

外部類的方法

局部?jī)?nèi)部類的方法

局部?jī)?nèi)部類子類的方法a=10,b=20,c=30,d=40

上述代碼CreateInnerClassMethod()方法中定義了兩個(gè)局部?jī)?nèi)部類LocalInnerClass和SubLocalInnerClass。編譯后會(huì)生成三個(gè)class文件:localInnerClassExample.class、localInnerClassExample$1LocalInnerClass.class和localInnerClassExample$1SubLocalInnerClass.class。局部?jī)?nèi)部類的class文件形式都是“外部類名$N內(nèi)部類名.class”。需要注意的是$符合后面多了一個(gè)數(shù)字,這是因?yàn)橛锌赡苡袃蓚€(gè)以上的同名局部類(處于不同方法中),所以使用一個(gè)數(shù)字進(jìn)行區(qū)分。

在項(xiàng)目的實(shí)際開(kāi)發(fā)中,很少用到局部?jī)?nèi)部類,這是因?yàn)榫植績(jī)?nèi)部類的作用域很小,只能在當(dāng)前方法中使用。7.4.3靜態(tài)內(nèi)部類

如果使用static來(lái)修飾一個(gè)內(nèi)部類,則這個(gè)內(nèi)部類就屬于外部類本身,而不屬于外部類的某個(gè)對(duì)象。因此使用static修飾的內(nèi)部類被稱為類內(nèi)部類,也稱為靜態(tài)內(nèi)部類。

靜態(tài)內(nèi)部類可以包含靜態(tài)成員,也可以包含非靜態(tài)成員。靜態(tài)內(nèi)部類是外部類的一個(gè)靜態(tài)成員,因此靜態(tài)內(nèi)部類的成員可以直接訪問(wèn)外部類的靜態(tài)成員,也可以通過(guò)外部類對(duì)象訪問(wèn)外部類的非靜態(tài)成員;外部類依然不能直接靜態(tài)內(nèi)部類的成員,但可以使用靜態(tài)內(nèi)部類的類名作為調(diào)用者來(lái)訪問(wèn)靜態(tài)內(nèi)部類的類成員,也可以使用靜態(tài)內(nèi)部類對(duì)象作為調(diào)用者來(lái)訪問(wèn)靜態(tài)內(nèi)部類的實(shí)例成員。

下述代碼示例了靜態(tài)內(nèi)部類的定義和使用,代碼所示如下。靜態(tài)內(nèi)部類7.4.3靜態(tài)內(nèi)部類【代碼7.13】StaticInnerClassExample.javapackageinner;publicclassStaticInnerClassExample{ privatestaticinta=20; privateintb=1; staticclassstaticInnerClass{ privateintc=10; privatestaticintd=30; publicvoidprint(){ System.out.println("靜態(tài)內(nèi)部類訪問(wèn)外部類成員顯示:a="+a+",b=" +newStaticInnerClassExample().b); } staticvoidtest(){ System.out.println("靜態(tài)內(nèi)部類中的靜態(tài)方法"); } }7.4.3靜態(tài)內(nèi)部類

publicvoiddisplay(){ System.out.println("外部類方法中調(diào)用靜態(tài)內(nèi)部類成員:c="+ newstaticInnerClass().c+",d="+staticInnerClass.d); //訪問(wèn)靜態(tài)內(nèi)部類中的靜態(tài)方法和實(shí)例方法 newstaticInnerClass().print(); staticInnerClass.test();}publicstaticvoidmain(String[]args){ StaticInnerClassExamplesce=newStaticInnerClassExample(); sce.display();//通過(guò)外部類創(chuàng)建靜態(tài)內(nèi)部類對(duì)象和調(diào)用靜態(tài)內(nèi)部類成員 StaticInnerClassExample.staticInnerClassss= newStaticInnerClassExample.staticInnerClass(); ss.print(); StaticInnerClassExample.staticInnerClass.test();}}程序運(yùn)行結(jié)果如下:外部類方法中調(diào)用靜態(tài)內(nèi)部類成員:c=10,d=30靜態(tài)內(nèi)部類訪問(wèn)外部類成員顯示:a=20,b=1靜態(tài)內(nèi)部類中的靜態(tài)方法靜態(tài)內(nèi)部類訪問(wèn)外部類成員顯示:a=20,b=1靜態(tài)內(nèi)部類中的靜態(tài)方法7.4.3匿名內(nèi)部類

匿名內(nèi)部類就是沒(méi)有類名的內(nèi)部類,適合創(chuàng)建那種只需要一次使用的類。創(chuàng)建匿名內(nèi)部類時(shí)會(huì)立即創(chuàng)建一個(gè)該類的實(shí)例,這個(gè)類定義立即消失,匿名內(nèi)部類不能重復(fù)使用。定義匿名內(nèi)部類的格式如下:new父類構(gòu)造方法(實(shí)參列表)|實(shí)現(xiàn)接口(){//匿名內(nèi)部類的類體部分}

從上面定義可以看出,匿名內(nèi)部類必須繼承一個(gè)父類,或?qū)崿F(xiàn)一個(gè)接口,但最多只能繼承一個(gè)父類或?qū)崿F(xiàn)一個(gè)接口。

下述代碼示例了匿名內(nèi)部類的定義格式,代碼如下所示。匿名內(nèi)部類7.4.3匿名內(nèi)部類publicclassAnonymousExample{ publicstaticvoidmain(String[]args){ System.out.println(newObject(){ publicStringtoString(){ return"匿名內(nèi)部類定義的基本格式使用"; } }); }}

上述代碼的含義是創(chuàng)建了一個(gè)匿名類對(duì)象,該匿名類重寫(xiě)Object父類的toString()方法。7.4.3匿名內(nèi)部類在使用匿名內(nèi)部類時(shí),要注意遵循以下幾個(gè)原則:(1)匿名內(nèi)部類不能是抽象類,因?yàn)橄到y(tǒng)在創(chuàng)建匿名內(nèi)部類時(shí),會(huì)立即創(chuàng)建匿名內(nèi)部類的對(duì)象。(2)匿名內(nèi)部類不能有構(gòu)造方法,因?yàn)槟涿麅?nèi)部類沒(méi)有類名,所以無(wú)法定義構(gòu)造方法,但匿名內(nèi)部類可以定義實(shí)例初始化塊,通過(guò)實(shí)例初始化塊類完成構(gòu)造方法需要完成的事情。(3)匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類,但非靜態(tài)的方法、屬性、內(nèi)部類是可以的。(4)只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例,最常用的創(chuàng)建匿名內(nèi)部類的方式是需要?jiǎng)?chuàng)建某個(gè)接口類型的對(duì)象。(5)一個(gè)匿名內(nèi)部類一定跟在new的后面,創(chuàng)建其實(shí)現(xiàn)的接口或父類的對(duì)象。(6)當(dāng)通過(guò)接口來(lái)創(chuàng)建匿名內(nèi)部類時(shí),匿名內(nèi)部類也不能顯示創(chuàng)建構(gòu)造方法,因此匿名內(nèi)部類只有一個(gè)隱式的無(wú)參數(shù)構(gòu)造方法,故new接口名后的括號(hào)里不能傳入?yún)?shù)值。(7)如果通過(guò)繼承父類來(lái)創(chuàng)建匿名內(nèi)部類時(shí),匿名內(nèi)部類將擁有和父類相似的構(gòu)造方法,即擁有相同的形參列表。(8)當(dāng)創(chuàng)建匿名內(nèi)部類時(shí),必須實(shí)現(xiàn)接口或抽象父類里的所有抽象方法,也可以重寫(xiě)父類中的普通方法。(9)如果匿名內(nèi)部類需要訪問(wèn)外部類的局部變量,則必須使用final修飾符來(lái)修飾外部類的局部變量。(10)匿名內(nèi)部類編譯以后,會(huì)產(chǎn)生以“外部類名$序號(hào)”為名稱的.class文件,序號(hào)以1~n排列,分別代碼1~n個(gè)匿名內(nèi)部類。7.4.3匿名內(nèi)部類下述代碼示例了匿名內(nèi)部類的定義和使用,代碼所示如下?!敬a7.14】AnonyInnerExample.javapackageinner;abstractclassDevice{ privateStringname; publicabstractdoublegetPrice(); publicDevice(){ } publicDevice(Stringname){ =name; } publicStringgetName(){ returnname; }}publicclassAnonyInnerExample{ publicvoidtest(Deviced){ System.out.println("購(gòu)買了一本"+d.getName()+",花掉了"+d.getPrice()+"元"); }7.4.3匿名內(nèi)部類 publicstaticvoidmain(String[]args){ AnonyInnerExampleai=newAnonyInnerExample(); //調(diào)用無(wú)參數(shù)構(gòu)造方法創(chuàng)建Device匿名實(shí)現(xiàn)類的對(duì)象 ai.test(newDevice(){ //初始化塊 { System.out.println("匿名內(nèi)部類的初始化塊"); } @Override publicdoublegetPrice(){ //TODOAuto-generatedmethodstub return38.5; } publicStringgetName(){ return"《面向?qū)ο蟪绦蛟O(shè)計(jì)Java》"; } });7.4.3匿名內(nèi)部類 //調(diào)用有參數(shù)構(gòu)造方法創(chuàng)建Device匿名實(shí)現(xiàn)類的對(duì)象 ai.test(newDevice("《面向?qū)ο蟪绦蛟O(shè)計(jì)Java》"){ @Override publicdoublegetPrice(){ return38.5; } }); }}程序運(yùn)行結(jié)果如下:購(gòu)買了一本《面向?qū)ο蟪绦蛟O(shè)計(jì)Java》,花掉了38.5元匿名內(nèi)部類的初始化塊購(gòu)買了一本《面向?qū)ο蟪绦蛟O(shè)計(jì)Java》,花掉了38.5元第5節(jié)part類之間的其他關(guān)系

除了繼承和實(shí)現(xiàn)外,依賴、關(guān)聯(lián)、聚合和組成也是類之間的重要關(guān)系類型。類之間的其他關(guān)系本節(jié)概述7.5.1依賴關(guān)系

依賴關(guān)系是最常見(jiàn)的一種類間關(guān)系,如果在一個(gè)類的方法中操作另外一個(gè)類的對(duì)象,則稱其依賴于第二個(gè)類。例如,方法的參數(shù)是某種對(duì)象類型,或者方法中的某些對(duì)象類型的局部變量,或者方法中調(diào)用了另一個(gè)類的靜態(tài)方法,這些都是依賴關(guān)系。依賴關(guān)系通常都是單向的。

下述代碼示例了兩個(gè)類之間的依賴關(guān)系,代碼如下所示。依賴關(guān)系7.5.1依賴關(guān)系【代碼7.15】RelyOnExample.javapackagerelation;classCar{voidrun(Stringcity){ System.out.println("歡迎,你來(lái)到"+city);}staticvoidprint(){ System.out.print("上汽大眾公司:");}}classPerson{voidtravel(Carcar){ Car.print();

溫馨提示

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