版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
學(xué)習(xí)導(dǎo)讀本章討論面向?qū)ο蟮木幊蹋∣OP)及其關(guān)鍵技術(shù):繼承和多態(tài)、接口、包。繼承性是軟件復(fù)用的一種形式,對(duì)降低軟件復(fù)雜性行之有效。繼承性同時(shí)是面向?qū)ο蟪绦蛟O(shè)計(jì)語言的特點(diǎn),采用對(duì)象但沒有繼承性的語言是基于對(duì)象的語言,但不是面向?qū)ο蟮恼Z言,這是兩者的區(qū)別。多態(tài)性允許以統(tǒng)一的風(fēng)格處理已存在的變量及相關(guān)的類,使增加系統(tǒng)中新功能變得容易。第6章繼承和多態(tài)教學(xué)重點(diǎn)與難點(diǎn)
理解繼承和復(fù)用的概念理解父類和子類掌握擴(kuò)展類編程理解多態(tài)性是如何擴(kuò)充和維護(hù)系統(tǒng)性能掌握如何建立包和接口第6章繼承第6章繼承6.1繼承的概念6.2擴(kuò)展類6.3多態(tài)與動(dòng)態(tài)綁定6.4構(gòu)造函數(shù)的繼承與重載6.5包6.6接口6.7本章小結(jié)6.1繼承的概念繼承性是面向?qū)ο蟪绦蛟O(shè)計(jì)語言的最主要的特點(diǎn),是其他語言(如面向過程語言)所沒有的。類之間的繼承關(guān)系是現(xiàn)實(shí)世界中遺傳關(guān)系的直接模擬,它表示類之間的內(nèi)在聯(lián)系以及對(duì)屬性和操作的共享,即子類可以沿用父類(被繼承類)的某些特征。當(dāng)然,子類也可以具有自己獨(dú)立的屬性和操作。繼承例如,飛行器、汽車和輪船可歸于交通工具類,飛行器類可以繼承交通工具類某些屬性和操作。除遺傳關(guān)系外,現(xiàn)實(shí)世界中還普遍存在著部分—整體關(guān)系。例如,飛機(jī)可由發(fā)動(dòng)機(jī)、機(jī)身、機(jī)械控制系統(tǒng)、電子控制系統(tǒng)等構(gòu)成。聚集關(guān)系。6.1.1繼承定義繼承性是軟件復(fù)用的一種形式。新類由已存在的類生成,通過保留它們的屬性和行為,并且根據(jù)新類的要求對(duì)性能加以修改,添加新的屬性和行為。如果子類只從一個(gè)父類繼承,則稱為單繼承;如果子類從一個(gè)以上父類繼承,則稱為多繼承。注意Java不支持多重繼承,但它支持“接口”概念。接口使Java獲得了多重繼承的許多優(yōu)點(diǎn),摒棄了相應(yīng)的缺點(diǎn)。繼承繼承提供了創(chuàng)建新類的一種方法,本質(zhì)特征是行為共享。繼承對(duì)開發(fā)者來說就是代碼共享。通過繼承創(chuàng)建的子類是作為另一個(gè)類的擴(kuò)充或修正所定義的一個(gè)類。子類從超類(父類)中繼承所有方法和變量。子類和超類之間是特化與范化的關(guān)系。自行車(超類)山地車賽車雙座自行車子類子類的聲明關(guān)鍵字extends:聲明一個(gè)類是派生自某個(gè)已知類。子類可以使用父類的protect和public可見的變量和方法,就像這些變量和方法是自己定義的一樣。Java中,如果類聲明時(shí)沒有聲明父類,那么缺省為Object類的子類。Java中的所有類都是Object類的子類。Object類定義了類的一些基本行為,如clone,toString,equals等。classCar{intcolorNumber;intdoorNumber;intspeed;
pushBreak(){…}addOil(){…}}
classTrashCarextendsCar{doubleamount;fillTrash(){…}}TrashCarmyCar=newTrashCar();myCar.addoil();Java中繼承的特點(diǎn)子類不從超類繼承構(gòu)造函數(shù)。單繼承性:Java編程語言允許一個(gè)類僅能直接擴(kuò)展自一個(gè)其它類,即extends關(guān)鍵字后面只能跟一個(gè)類名。單繼承性使代碼更可靠。Java中,如果類聲明時(shí)沒有聲明父類,那么缺省為Object類的子類。Java中的所有類都是Object類的子類。類庫文檔:對(duì)一個(gè)繼承的方法或變量的描述只存在于對(duì)該成員進(jìn)行定義的類的API文檔中。※
SuperclassesandSubclassesUMLDiagram父類名跟在extends關(guān)鍵字后面,用來說明當(dāng)前類是哪個(gè)已經(jīng)存在類的子類,存在繼承關(guān)系。定義雇員類Employee的兩個(gè)子類:一般雇員類monEmployee主管類:ManagerEmployee子類從父類繼承有兩個(gè)主要的方面:(1)屬性的繼承。例如,公司是一個(gè)父類,一個(gè)公司有名稱、地址、經(jīng)理、雇員等,這些都屬于結(jié)構(gòu)方面。(2)方法的繼承。一個(gè)父類定義了若干操作,如一個(gè)公司要有項(xiàng)目、利潤(rùn)、任命經(jīng)理、錄用職工等操作,子公司也將繼承這些行為。6.2.1繼承關(guān)系定義6.2擴(kuò)展類classCommonEmployeeextendsEmployee
//子類1:
{
intm_ManagerNo;//定義類屬性m_ManagerNo,代表雇員上司的編號(hào)}classManagerEmployeeextendsEmployee//子類2:{
intm_SecretaryNo;//定義類屬性m_SecretaryNo,代表秘書的編號(hào)}兩個(gè)子類聲明類頭-父類名6.2.2屬性繼承與隱藏盡管Employee類是一個(gè)父類,但是并不因?yàn)樗歉割惥鸵馕吨懈嗟墓δ?。恰恰相反,子類比它們的父類具有更多的功能。因?yàn)樽宇愂歉割惖臄U(kuò)展,增加了父類沒有的屬性和方法。(1)子類不能訪問父類的private成員,但子類可以訪問其父類的public,(2)protected訪問是public和private訪問之間一個(gè)保護(hù)性的中間層次。(3)由于被繼承的父類成員沒有在子類聲明中列出,但是這些成員確實(shí)存在于子類中。6.2.2
屬性繼承與隱藏
Manger類增添了一個(gè)新的字段用于存儲(chǔ)獎(jiǎng)金,并且增添了一個(gè)新方法用于設(shè)置它的值:classManagerextendsEmployee{……publicvoidsetBonus(doubleb){bonus=b;}privatedoublebonus;}【例4.1】計(jì)算箱子的體積和重量?!纠?.2】子類構(gòu)造器C調(diào)用基類的構(gòu)造器A來初始化基類。6.2.3方法繼承、覆蓋與重載
對(duì)于Manager對(duì)象,可以使用getName和getHireDay等方法。即使這些方法沒有明顯地在Manager類中定義,它們也自動(dòng)地從Employee類中繼承過來了。2.方法覆蓋
方法的覆蓋是指:子類定義同名方法來覆蓋父類的方法,是多態(tài)技術(shù)的一個(gè)實(shí)現(xiàn)。當(dāng)父類方法在子類中被覆蓋時(shí),通常是子類版本調(diào)用父類版本,并做一些附加的工作。1.方法繼承關(guān)于覆蓋應(yīng)注意的事項(xiàng)(1)不使用super而希望引用父類方法會(huì)導(dǎo)致無限的遞歸,因?yàn)樽宇惙椒▽?shí)際上是在調(diào)用它自己。(2)當(dāng)通過父類引用調(diào)用一個(gè)方法時(shí),Java會(huì)正確地選擇與那個(gè)對(duì)象對(duì)應(yīng)的類的覆蓋方法。(3)方法覆蓋中,子類在重新定義父類已有的方法時(shí),應(yīng)保持與父類完全相同的方法頭聲明,即與父類完全相同的方法名、返回值和參數(shù)列表。(4)子類可以添加字段,也可以添加方法或者覆蓋父類中的方法。然而,繼承不能去除父類中的任何字段和方法?!?/p>
this與super如果子類聲明了一個(gè)與父類的成員變量同名的成員變量,則稱父類的該成員變量被隱藏(hiding)如果子類聲明了一個(gè)與父類的成員方法同名的成員方法,則稱父類的該成員方法被重寫(overriding)關(guān)鍵字this
和super分別用來指明子類和父類中同名的成員變量或成員方法當(dāng)父類的成員變量、子類的成員變量和類中方法使用的局部變量三者同名,或其中的兩者同名時(shí),可以使用關(guān)鍵字this和super來指定所要使用的變量。譬如,設(shè)有類A和類B,類B是類A的子類;類A和類B中都聲明了成員變量x。另外,類B中含有方法m,方法m中聲明了局部變量x。于是,這里存在三個(gè)同名的變量:類A中的成員變量x,類B的成員變量x,以及方法m中的局部變量x。在類B的方法m中,可以用super.x,this.x和x分別表示上述三個(gè)變量,如例所示?!?/p>
例:用this和super區(qū)別同名的變量classA{ intx;
//類A中聲明了成員變量x ┇}classBextendsA{ //類B繼承類A,也繼承了類A的成員變量x intx; //類B中又聲明了成員變量x
┇
voidm() { intx; //方法m聲明了自己的局部變量x ┇ super.x=2; //super.x是其所在類的父類即類A的x this.x=1; //this.x是其所在類即類B的x x=100; //x是方法本身的局部變量x ┇ }}※
this和super還可以分別用來指明子類和父類中的同名方法
super區(qū)別同名的方法。classSuperCa{intx;
SuperCa()
{
x=5;System.out.println("SuperCax="+x);
}
voiddoCa(){
System.out.println("SuperCa.doCa()");
}}
classSubCaextendsSuperCa{intx;
SubCa(){super();//調(diào)用父類的構(gòu)造方法
x=8;System.out.println("SubCax="+x);
}
voiddoCa(){
super.doCa();
//調(diào)用父類的方法
System.out.println("insubCa.doCa()");System.out.println("super.x="+super.x);
}
}
說明:本例兩次使用了super關(guān)鍵字。第一次是子類的構(gòu)造方法中調(diào)用父類的構(gòu)造方法,用了super()語句;第二次是在子類SubCa的doCa()方法中調(diào)用父類的doCa()方法時(shí),用了super.doCa()語句。
3.覆蓋當(dāng)用于子類的行為與父類的行為不同時(shí),覆蓋機(jī)制允許子類可以修改從父類繼承來的行為。覆蓋就是在子類中創(chuàng)建一個(gè)與父類方法有不同功能的方法,但具有相同的名稱、返回類型和參數(shù)表。若參數(shù)表不同,則不是覆蓋,而是重載。若參數(shù)表相同,但返回值不同,則編譯出錯(cuò)。classCar{intcolorNumber;intdoorNumber;intspeed;
voidpushBreak(){speed=0;}voidaddOil(){…}}
classTrashCarextends
Car{doubleamount;voidfillTrash(){…}voidpushBreak(){speed=speed-10;}}【例4.3】子類Employee重寫父類的getInfo()方法。super關(guān)鍵字通常當(dāng)覆蓋一個(gè)方法時(shí),實(shí)際目的不是要更換現(xiàn)有的行為,而是要在某種程度上擴(kuò)展該行為。
此時(shí)應(yīng)先執(zhí)行父類的行為,然后再執(zhí)行擴(kuò)展部分的行為。這種情況下用super關(guān)鍵字調(diào)用父類的行為。classCar{intcolorNumber;intdoorNumber;intspeed;
void
pushBreak(){speed=0;}voidaddOil(){…}}
classTrashCarextends
Car{doubleamount;voidfillTrash(){…}
voidpushBreak(){super.pushBreak();speed+=5;}}繼承演示(例6.1)classCylinderextendsCircle{privatedoublelength;publicCylinder()//Defaultconstructor{super();length=1.0;}//Constructacylinderwithspecifiedradius,andlengthpublicCylinder(doubleradius,doublelength){this(radius,"white",1.0,length);}
//Constructacylinderwithspecifiedradius,weight,color,andlengthpublicCylinder(doubleradius,Stringcolor,doubleweight,doublelength){super(radius,color,weight);this.length=length;}※
繼承演示(例6.1)publicdoublegetLength()//Gettermethodforlength{returnlength;}
publicvoidsetLength(doublelength)//Settermethodforlength{this.length=length;}
publicdoublefindArea()//Findcylindersurfacearea{return2*super.findArea()+(2*getRadius()*Math.PI)*length;}publicdoublefindVolume()//Findcylindervolume{returnsuper.findArea()*length;}
//Overridetheequals()methoddefinedintheObjectclasspublicbooleanequals(Cylindercylinder){return(this.radius==cylinder.getRadius())&&(this.length==cylinder.getLength());}//OverridethetoString()methoddefinedintheObjectclasspublicStringtoString(){return"[Cylinder]radius="+radius+"andlength“+length;}}繼承演示(例6.1)//TestCylinder.java:UseinheritancepublicclassTestCylinder{publicstaticvoidmain(String[]args){//CreateaCylinderobjectanddisplayitspropertiesCylindermyCylinder=newCylinder(5.0,2.0);System.out.println("Thelengthis"+myCylinder.getLength());System.out.println("Theradiusis"+myCylinder.getRadius());System.out.println("Thevolumeofthecylinderis"+myCylinder.findVolume());System.out.println("Theareaofthecircleis"+myCylinder.findArea());}}繼承演示(例6.1)//Circle.java:ThecircleclassthatextendsGeometricObjectpublicclassCircleextendsGeometricObject{protecteddoubleradius;//DefaultconstructorpublicCircle(){this(1.0,"white",1.0);}//ConstructcirclewithspecifiedradiuspublicCircle(doubleradius){super("white",1.0);this.radius=radius;}//Constructacirclewithspecifiedradius,weight,andcolorpublicCircle(doubleradius,Stringcolor,doubleweight){super(color,weight);this.radius=radius;}繼承演示(例6.1)publicdoublegetRadius()//Gettermethodforradius{returnradius;}publicvoidsetRadius(doubleradius)//Settermethodforradius{this.radius=radius;}//ImplementthefindAreamethoddefinedinGeometricObject
publicdoublefindArea(){returnradius*radius*Math.PI;}//ImplementthefindPerimetermethoddefinedinGeometricObjectpublicdoublefindPerimeter(){return2*radius*Math.PI;}//Overridetheequals()methoddefinedintheObjectclasspublicbooleanequals(Circlecircle){returnthis.radius==circle.getRadius();}//OverridethetoString()methoddefinedintheObjectclasspublicStringtoString(){return"[Circle]radius="+radius;}}繼承演示(例6.1)//GeometricObject.java:TheabstractGeometricObjectclasspublicabstractclassGeometricObject{protectedStringcolor;protecteddoubleweight;//DefaultconstructprotectedGeometricObject(){color="white";weight=1.0;}//ConstructageometricobjectprotectedGeometricObject(Stringcolor,doubleweight){this.color=color;this.weight=weight;}//GettermethodforcolorpublicStringgetColor(){returncolor;}繼承演示(例6.1)//SettermethodforcolorpublicvoidsetColor(Stringcolor){this.color=color;}//GettermethodforweightpublicdoublegetWeight(){returnweight;}//SettermethodforweightpublicvoidsetWeight(doubleweight){this.weight=weight;}//AbstractmethodpublicabstractdoublefindArea();//AbstractmethodpublicabstractdoublefindPerimeter();}4.方法重載重載的定義:可以用相同的方法名但不同的參數(shù)表來定義方法(參數(shù)表中參數(shù)的數(shù)量、類型或次序有差異),這稱為方法重載。
重載(overloading):當(dāng)多個(gè)方法具有相同的名字而含有不同的參數(shù)時(shí),便發(fā)生重載。編譯器必須挑選處調(diào)用哪個(gè)方法。它通過將在不同方法頭部中的參數(shù)類型和在特定的方法調(diào)用中使用值的類型進(jìn)行比較,從而挑選出正確的方法。
重載重載指在同一個(gè)類中至少有兩個(gè)方法用同一個(gè)名字,但有不同的參數(shù)。重載使得從外部來看,一個(gè)操作對(duì)于不同的對(duì)象有不同的處理方法。調(diào)用時(shí),根據(jù)參數(shù)的不同來區(qū)別調(diào)用哪個(gè)方法。方法的返回類型可以各不相同,但它不足以使返回類型變成唯一的差異。重載方法的參數(shù)表必須不同。
classCar{intcolorNumber;intdoorNumber;intspeed;
voidpushBreak(){speed=0;}
voidpushBreak(intaDeltaSpeed){speed-=aDeltaSpeed;}voidadd_oil(){…}}
5.重載和覆蓋的區(qū)別相同點(diǎn):都涉及兩個(gè)同名的方法。不同點(diǎn):類層次重載涉及的是同一個(gè)類的兩個(gè)同名方法;覆蓋涉及的是子類的一個(gè)方法和父類的一個(gè)方法,這兩個(gè)方法同名。參數(shù)和返回值重載的兩個(gè)方法具有不同的參數(shù),可以有不同返回值類型;覆蓋的兩個(gè)方法具有相同的參數(shù),返回值類型必需相同?!?/p>
例6.2覆蓋父類中的方法classCylinderextendsCircle{privatedoublelength;//DefaultconstructorpublicCylinder(){super();length=1.0;}//ConstructacylinderwithspecifiedradiusandlengthpublicCylinder(doubler,doublel){super(r);length=l;}
//GettermethodforlengthpublicdoublegetLength(){returnlength;}//FindcylindersurfaceareapublicdoublefindArea(){
return2*super.findArea()+(2*getRadius()*Math.PI)*length;}//FindcylindervolumepublicdoublefindVolume(){
returnsuper.findArea()*length;}}為什么Cylinder的子類不能訪問Circle中的findArea方法?※
6.2.4在子類中使用構(gòu)造函數(shù)關(guān)于子類構(gòu)造函數(shù)的規(guī)律總結(jié)如下:(1)子類構(gòu)造函數(shù)總是先調(diào)用(顯式的或隱式地)其父類的構(gòu)造函數(shù),以創(chuàng)建和初始化子類的父類成員。(2)構(gòu)造函數(shù)不能繼承,它們只屬于定義它們的類。如果把一個(gè)對(duì)象指定為其父類的引用,那么允許把這個(gè)對(duì)象轉(zhuǎn)換回它自己原來的類型,為了向該對(duì)象傳送一些在父類中沒有的信息,必須這樣做。(3)當(dāng)創(chuàng)建一個(gè)子類對(duì)象時(shí),子類構(gòu)造函數(shù)首先調(diào)用父類的構(gòu)造函數(shù)并執(zhí)行,接著才執(zhí)行子類構(gòu)造函數(shù)。6.2.5父類對(duì)象與子類對(duì)象的關(guān)系調(diào)用過程:e.getSalary()程序會(huì)選擇正確的getSalary方法。注意盡管e的聲明類型是Employee.當(dāng)e指向一個(gè)Employee對(duì)象時(shí),e.getSalary()會(huì)調(diào)用Employee類中的getSalary方法;而當(dāng)e指向一個(gè)Manager對(duì)象時(shí),getSalary()方法就變成了Manager類的getSalary()方法。虛擬機(jī)知道e所指對(duì)象的實(shí)際類型,因此它會(huì)調(diào)用正確的方法。事實(shí)上,一個(gè)對(duì)象變量(如e)可以指向多種實(shí)際類型這種現(xiàn)象稱為“多態(tài)”。在運(yùn)行時(shí)自動(dòng)選擇正確的方法進(jìn)行調(diào)用稱作動(dòng)態(tài)綁定。6.3多態(tài)與動(dòng)態(tài)綁定多態(tài)(Polymorphism)提高了程序可擴(kuò)充性,調(diào)用多態(tài)性行為的軟件傳送給對(duì)象的消息(即方法調(diào)用)與對(duì)象的類型無關(guān),因此能響應(yīng)已有消息的新類型可以直接加入系統(tǒng),而不用修改基本系統(tǒng)。在運(yùn)行時(shí)自動(dòng)選擇正確的方法進(jìn)行調(diào)用稱作動(dòng)態(tài)綁定(dynamicbinding)。6.3.1多態(tài)對(duì)于數(shù)據(jù)來說,繼承是否為正確的設(shè)計(jì)可以用一個(gè)簡(jiǎn)單的規(guī)則來判斷?!癷s-a”規(guī)則表明子類的每一個(gè)對(duì)象都是一個(gè)超類的對(duì)象。例如,每一個(gè)經(jīng)理是一個(gè)員工。然而,只有經(jīng)理類是員工類的子類才是有意義的。很明顯,反過來就不行了——并不是每個(gè)員工都是經(jīng)理。還有一個(gè)明確敘述“is-a”規(guī)則的方法是替代原則。該原則規(guī)定無論何時(shí),如果程序需要一個(gè)超類對(duì)象,都可以用一個(gè)子類對(duì)象來代替。
6.3.2動(dòng)態(tài)綁定理解調(diào)用一個(gè)對(duì)象方法的機(jī)制是非常重要的。下面具體介紹:(1)編譯器檢查對(duì)象的聲明類型和方法名。(2)接著,編譯器檢查方法調(diào)用中的參數(shù)類型。如果在所有的叫做f的方法中有一個(gè)其參數(shù)類型同調(diào)用提供的參數(shù)類型最匹配,那么該方法就會(huì)被選擇調(diào)用。這個(gè)過程稱作超載選擇。(前面Circle類的構(gòu)造函數(shù))(3)當(dāng)程序運(yùn)行并且使用動(dòng)態(tài)綁定來調(diào)用一個(gè)方法時(shí),那么虛擬機(jī)必須調(diào)用同x所指向的對(duì)象的實(shí)際類型相匹配的方法版本。動(dòng)態(tài)綁定是非常重要的特性:它能使程序變得可擴(kuò)展而無需重編譯已存代碼。6.3.3父類對(duì)象與子類對(duì)象的使用與轉(zhuǎn)化this表示的是當(dāng)前對(duì)象本身,更準(zhǔn)確地說,this代表了當(dāng)前對(duì)象的一個(gè)引用。對(duì)象的引用可以理解為對(duì)象的另一個(gè)名字,通過引用可以順利地訪問對(duì)象,包括修改對(duì)象的屬性、調(diào)用對(duì)象的方法。1.this現(xiàn)介紹程序里父類對(duì)象與子類對(duì)象間的指代使用和轉(zhuǎn)化。this和super是常用來指代父類對(duì)象與子類對(duì)象的關(guān)鍵字.super表示的是當(dāng)前對(duì)象的直接父類對(duì)象,是當(dāng)前對(duì)象的直接父類對(duì)象的引用。所謂直接父類是相對(duì)于當(dāng)前對(duì)象的其他“祖先”而言的。2.super提供一個(gè)構(gòu)造函數(shù):publicManager(Stringn,doubles,intyear,intmonth,intday){super(n,s,year,month,day);bonus=0;}這里關(guān)鍵字super具有不同的意義。代碼:super(n,s,year,month,day);的意思是“調(diào)用Employee父類的構(gòu)造函數(shù),同時(shí)帶有n、s、year、month以及day參數(shù)”。6.3.3父類對(duì)象與子類對(duì)象的使用與轉(zhuǎn)化父類對(duì)象與和子類對(duì)象的轉(zhuǎn)化需要注意如下的原則:(1)子類對(duì)象可以被視為是其父類的一個(gè)對(duì)象;(2)父類對(duì)象不能當(dāng)成是其某一個(gè)子類的對(duì)象;(3)如果一個(gè)方法的形式參數(shù)定義的是父類對(duì)象,那么調(diào)用這個(gè)方法時(shí),可以使用子類對(duì)象作為形式參數(shù);(4)如果父類對(duì)象引用指向的實(shí)際是一個(gè)子類對(duì)象,那么這個(gè)父類對(duì)象的引用可以用強(qiáng)制類型轉(zhuǎn)換轉(zhuǎn)化成子類對(duì)象的引用。
※
例如,B類是A類的子類或間接子類,當(dāng)子類B創(chuàng)建一個(gè)對(duì)象,并把這個(gè)對(duì)象賦給類A的引用變量,那么,稱這個(gè)A類對(duì)象a是子類對(duì)象b的向上轉(zhuǎn)型的對(duì)象。這個(gè)向上轉(zhuǎn)型的對(duì)象還可以通過強(qiáng)制類型轉(zhuǎn)換還原成它本來的類型,被稱為對(duì)象的向下轉(zhuǎn)型。classA{}classBextendsA{}Aa;Bb1=newB();a=b1; //向上轉(zhuǎn)型Bb2=(B)a; //向下轉(zhuǎn)型
向上轉(zhuǎn)型的對(duì)象具有如下特點(diǎn):(1)向上轉(zhuǎn)型對(duì)象不能操作子類新增的成員屬性和方法(失掉了這部分功能)。(2)向上轉(zhuǎn)型對(duì)象可以操作子類繼承或隱藏的成員變量,也可以使用子類繼承的或重寫的方法。(3)向上轉(zhuǎn)型對(duì)象操作子類繼承或重寫的方法時(shí),就是通知對(duì)應(yīng)的子類對(duì)象去調(diào)用這些方法。因此,如果子類重寫了父類的某個(gè)方法后,對(duì)象的向上轉(zhuǎn)型對(duì)象調(diào)用這個(gè)方法時(shí),一定是調(diào)用了這個(gè)重寫的方法。(4)可以將向上轉(zhuǎn)型對(duì)象再強(qiáng)制轉(zhuǎn)換到它本來的類型,該對(duì)象又具備了其所有屬性和方法?!纠?.5】測(cè)試對(duì)象轉(zhuǎn)型的特點(diǎn),使用instanceof判斷一個(gè)實(shí)例對(duì)象是否屬于某個(gè)類。instanceof可以判斷一個(gè)引用變量所指向的對(duì)象是否屬于某個(gè)類,所以在執(zhí)行下面第一條語句返回true,執(zhí)行第二條語句發(fā)生了對(duì)象的向上轉(zhuǎn)型,Person類的引用變量指向 System.out.println(pinstanceofEmployee); p=newEmployee("Mary",3000);Employee對(duì)象,如圖4.1的箭頭①。但這時(shí)引用變量p所能訪問的內(nèi)容只限于Employee對(duì)象的父類Person對(duì)象,也就是箭頭②所指向的區(qū)域。在執(zhí)行下面的這條語句時(shí),發(fā)生了對(duì)象的向下轉(zhuǎn)型。 Employeee1=(Employee)p; Employee類的引用變量e1同樣指向Employee對(duì)象。這時(shí)引用變量e1能訪問Employee對(duì)象的所有內(nèi)容,也就是箭頭③所指向的區(qū)域。圖4.1程序執(zhí)行的內(nèi)存布局動(dòng)態(tài)綁定例子由于多態(tài)機(jī)制,Java調(diào)用一個(gè)對(duì)象的方法時(shí)采用動(dòng)態(tài)綁定的方式。動(dòng)態(tài)綁定就是根據(jù)對(duì)象的類型決定調(diào)用哪個(gè)方法,而不是引用的類型。例如:classGeometricObject{ publicvoiddraw(){…}}classEllipseextendsGeometricObject{ publicvoiddraw(){…} publicvoidgetCenter(){…}}classCircleextendsEllipse{ publicvoiddraw(){…} publicdoublegetArea(){…}}GeometricObjectg=newCircle(); //父類型引用指向子類型對(duì)象//圓是一種幾何對(duì)象g.draw(); //draw調(diào)用的是哪個(gè)類的方法?如果g換成Circle類引用呢? //如果Circle類不覆蓋draw方法,調(diào)用的是哪個(gè)類的方法?doubled=g.getArea(); //編譯時(shí)能否通過?!?/p>
動(dòng)態(tài)綁定示意圖Circle引用Circle對(duì)象Circle類Ellipse類GeometricObject類drawgetCentergetAreaGeometricObject引用Circle對(duì)象Circle類Ellipse類GeometricObject類draw引用的類型限制了能夠看到的對(duì)象的能力。實(shí)際調(diào)用的是對(duì)象所屬類的方法,與引用的類型無關(guān)。※
classTestA{publicvoidstart(){System.out.println("TestA");}}publicclassTestBextendsTestA{publicvoidstart(){System.out.println("TestB");}
publicstaticvoidmain(Stringarg[]){TestBb=newTestB();TestAa=(TestA)b;a.start();}}※
最后結(jié)果是"TestB".解釋如下:TestBb=newTestB();//實(shí)例化一個(gè)叫做b的TestB類對(duì)象。TestAa=(TestA)b;//由于TestB類繼承自TestA類,因此TestB類是TestA類的子類。//有小轉(zhuǎn)到大可以自動(dòng)轉(zhuǎn)換,所以不用強(qiáng)轉(zhuǎn),直接寫成:TestAa=b//綜上,就是TestAa=newTestB();//父類的引用指向子類,屬于多態(tài)。//原本應(yīng)該輸出a里的start()方法,可是發(fā)現(xiàn)子類里也有個(gè)start()方法,所以就執(zhí)行子類的方法。//所以輸出b的start()內(nèi)容,這是方法重寫。例6.3測(cè)試多態(tài)性publicclassTestPolymorphism{//Mainmethodpublicstaticvoidmain(String[]args){//Declareandinitializetwogeometricobjects
GeometricObjectgeoObject1=newCircle(5);GeometricObjectgeoObject2=newRectangle(5,3);System.out.println("Thetwoobjectshavethesamearea?"+equalArea(geoObject1,geoObject2));//DisplaycircledisplayGeometricObject(geoObject1);//DisplayrectangledisplayGeometricObject(geoObject2);}
//AmethodforcomparingtheareasoftwogeometricobjectsstaticbooleanequalArea(GeometricObjectobject1,GeometricObjectobject2){
returnobject1.findArea()==object2.findArea();}//AmethodfordisplayingageometricobjectstaticvoiddisplayGeometricObject(GeometricObjectobject){System.out.println();System.out.println(object.toString());
System.out.println("Theareais"+object.findArea());System.out.println("Theperimeteris"+object.findPerimeter());}}【例4.6】Polymorphism程序滿足多態(tài)條件,根據(jù)對(duì)象的類型調(diào)用恰當(dāng)?shù)姆椒ā?.4構(gòu)造函數(shù)的繼承與重載6.4.1默認(rèn)字段初始化構(gòu)造函數(shù)的作用是來定義對(duì)象的初始狀態(tài)。然而由于對(duì)象的構(gòu)造如此重要,Java還另外提供了一些不同的機(jī)制來編寫構(gòu)造函數(shù)。如果在構(gòu)造函數(shù)中沒有明確地給某個(gè)字段賦值,那么此字段會(huì)被自動(dòng)地賦值以一個(gè)默認(rèn)值:若是數(shù)字則被賦值以0,若是布爾類型則被賦值以false,若是對(duì)象引用則被賦值以null。但使用默認(rèn)值被認(rèn)為是一種糟糕的編程做法。因?yàn)?,如果字段以不可見的形式被初始化?huì)使得別人很難讀懂程序。6.4.2默認(rèn)構(gòu)造函數(shù)默認(rèn)構(gòu)造函數(shù)是指沒有參數(shù)的構(gòu)造函數(shù)(這種構(gòu)造函數(shù)有時(shí)也稱作無參數(shù)構(gòu)造函數(shù))。例如,下面是—個(gè)Employee類的默認(rèn)構(gòu)造函數(shù):publicEmployee(){name=””;salary=0;hireDay=newDate();}如果編寫了一個(gè)沒有構(gòu)造函數(shù)的方法,則系統(tǒng)會(huì)自動(dòng)為此方法提供一個(gè)默認(rèn)構(gòu)造函數(shù)。此默認(rèn)構(gòu)造函數(shù)將所有的實(shí)例字段初始化為默認(rèn)值。
6.4.3顯式字段初始化由于在類中可以重載構(gòu)造函數(shù)方法,所以可以采用多種方式來設(shè)置類中實(shí)例字段的初始狀態(tài)不管什么樣的構(gòu)造函數(shù)調(diào)用,確保每個(gè)實(shí)例字段都被設(shè)置為某個(gè)有意義的值是一種很好的習(xí)慣。在類的定義中,可以簡(jiǎn)單地把一個(gè)值賦值給任何字段。例如,privateStringname=”lili”在執(zhí)行構(gòu)造函數(shù)前,此賦值會(huì)被執(zhí)行。當(dāng)類中所有的構(gòu)造函數(shù)都需要把某一特定的實(shí)例字段賦值以相同的值時(shí),此語法非常有用。6.4.4參數(shù)名當(dāng)編寫小的構(gòu)造函數(shù)時(shí),一般選擇單個(gè)字母作為參數(shù)名。publicEmployee(Stringn,doubles){name=n;salary=s;}然而,這么做的缺點(diǎn)是需要閱讀代碼才能知道參數(shù)n和s表示的是什么。一些程序員在每個(gè)參數(shù)前加一前綴“a”:6.4.5調(diào)用另一個(gè)構(gòu)造函數(shù)關(guān)鍵字this指向隱式參數(shù)。此外,此關(guān)鍵字還有另一種含義。如果構(gòu)造函數(shù)第一個(gè)語句具有形式this(……),那么此構(gòu)造函數(shù)調(diào)用此類中的另一個(gè)構(gòu)造函數(shù)。下面是一個(gè)典型的實(shí)例:publicEmployee(doubles){//callsEmployee(String,double)this(“Employee#”+nextId,s);nextId++;}6.4.6初始化塊在Java中實(shí)際上還有第三種機(jī)制,它叫做初始化塊。在類聲明中可以包含任意數(shù)量的代碼塊。只要構(gòu)造了此類的一個(gè)對(duì)象,這些代碼塊就會(huì)被執(zhí)行。例如:classEmployee{publicEmployee(Stringn,doubles){name=n;salary=s;}}publicEmployee(){name=””;salary=0;}6.4.6初始化塊//對(duì)象初始化模塊{id=nextId;nextId++;}privateStringname;privatedoublesalary;privateintid;privatestaticintnextId;}在這個(gè)例子中,id字段在對(duì)象初始化塊中被初始化,而不管是哪個(gè)構(gòu)造函數(shù)構(gòu)造了一個(gè)對(duì)象。初始化塊首先被運(yùn)行,然后構(gòu)造函數(shù)的主體部分被執(zhí)行。
6.5包6.5.1包用途Java允許把多個(gè)類收集在一起成為一組,稱作包(package)。包便于組織任務(wù),以及使自己的任務(wù)和其他人提供的代碼庫相分離。標(biāo)準(zhǔn)Java庫被分類成許多的包,其中包括java.1ang、java.util和等等。標(biāo)準(zhǔn)Java包是分層次的。就像在硬盤上嵌套有各級(jí)子目錄一樣,可以通過層次嵌套組織包。所有的Java包都在Java和Javax包層次內(nèi)。6.5.2創(chuàng)建包已經(jīng)看到,已有的庫,比如JavaAPI中的類和接口,可以導(dǎo)入到Java程序中。JavaAPI中的每一個(gè)類和接口屬于一個(gè)特定的包。它包含一組相關(guān)聯(lián)的類和接口,實(shí)際是對(duì)類和接口進(jìn)行組織的目錄結(jié)構(gòu)。例如,假定文件名是MyClass.java。它意味著在那個(gè)文件有一個(gè)、而且只能有一個(gè)public類。而且那個(gè)類的名字必須是MyClass(包括大小寫形式):packagemypackage;publicclassMyClass{……}
6.5.2創(chuàng)建包創(chuàng)建可復(fù)用的類的步驟簡(jiǎn)要說明如下:(1)定義一個(gè)public類。如果類不是public,它只能被同一包中的其他類使用。(2)選擇一個(gè)包名,并把package語句加到可復(fù)用的類的源代碼文件中。(3)編譯這個(gè)類。這樣,它就被放到適當(dāng)?shù)陌夸浗Y(jié)構(gòu)中,以供編譯器和解譯器使用。(4)把這個(gè)可復(fù)用的類導(dǎo)入到需要用它的程序中?,F(xiàn)在就可以使用它了。注意在Java語言中可以出現(xiàn)在類定義的括號(hào)外面的僅有兩個(gè)語句,它們是package和import。6.5.3包引用---每個(gè)類名前加上完整的包名例如,給出一個(gè)指向此包中的類的快捷方式。一旦使用import(導(dǎo)入)了以后,就不再需要給出完整的包名??梢砸胍粋€(gè)特定的類,也可以引入整個(gè)包。import語句要放在源文件的頭部(但在所有package語句的下面)。例如,可以通過下面的語句引入在java.util包中的所有的類:importjava.util.*;然后,就可以使用Datetoday=newDate();而不需要在前面加上包名。也可以引入包中某個(gè)特定的類:importjava.util.Date;6.5.3包引用---向包中添加類要把類放入一個(gè)包中,必須把此包的名字放在源文件頭部,并且放在對(duì)包中的類進(jìn)行定義的代碼之前。例如,在文件Employee.java的開始部分如下:packagecom.horstmann.corejava;publicclassEmployee{……}把包中的文件放入與此完整的包名相匹配的子目錄中。例如,在包c(diǎn)om.horstmann.corejava中的所有的類文件都必須放在子目錄com/horstmann/core.java(Windows下的com\horstmann\corejava)下。這是最簡(jiǎn)單的一種方法,在本章的后面可以看到更多的選項(xiàng)。
6.5.3包引用--定位類類被存儲(chǔ)在文件系統(tǒng)的子目錄中。類的路徑必須與所在包名相匹配。在前面的例子中,包目錄com/horstmann/corejava是程序目錄的一個(gè)子目錄。然而這樣安排很不靈活。一般,有多個(gè)程序需要訪問包文件。為了使包可以在多個(gè)程序間共享,需要做以下事情:1)把類放在一個(gè)或多個(gè)特定的目錄中,比如/home/user/classdir。此目錄是包樹的基本目錄。如果加入了類com.horstmann.corejava.Employee,那么此類文件必須位于子目錄/horstmann/corejava下。2)設(shè)置類路徑。類路徑是其子目錄包含類文件的所有基本目錄的集合。6.5.3包引用--標(biāo)記包作用域已經(jīng)接觸過public和private訪問指示符。被標(biāo)記為Public的部件可以被任何類使用,而私有部件只能被定義它們的類使用。如果沒有指定public或private,那么部件(即類、方法或變量)可以被同一個(gè)包中的所有方法訪問。6.5.4JavaAPI包為了簡(jiǎn)化面向?qū)ο蟮木幊踢^程,Java系統(tǒng)事先設(shè)計(jì)并實(shí)現(xiàn)了一些體現(xiàn)了常用功能的標(biāo)準(zhǔn)類,如用于輸入/輸出的類,用于數(shù)學(xué)運(yùn)算的類,用于圖形用戶界面設(shè)計(jì)的類,用于網(wǎng)絡(luò)處理的類等。這些系統(tǒng)標(biāo)準(zhǔn)類根據(jù)實(shí)現(xiàn)的功能不同,可以劃分成不同的集合,每個(gè)集合是一個(gè)包,合稱為類庫??梢砸眠@些包,也可以創(chuàng)建自己的包。Java的類庫是系統(tǒng)提供的已實(shí)現(xiàn)的標(biāo)準(zhǔn)類的集合,是Java編程的API,它可以幫助開發(fā)者方便、快捷地開發(fā)Java程序。虛擬機(jī)如何定位類虛擬機(jī)執(zhí)行某個(gè)類時(shí),需要找到該類文件(.class文件)以及該類用到的其他的類。類被存儲(chǔ)在文件系統(tǒng)的子目錄中,路徑必須與所在包名相匹配。也可以將多個(gè)類文件及其目錄結(jié)構(gòu)保存在一個(gè)jar文件中??梢允褂胘ava命令的-classpath選項(xiàng)設(shè)置類的查找路徑,可以簡(jiǎn)寫為-cp,多個(gè)路徑之間用;隔開。如:java–classpath.;hello
Hello;Java虛擬機(jī)在加載類的時(shí)候以這樣一種方式查找具體的類文件:classpath+包存儲(chǔ)的目錄+具體的類文件。如classpath中有一個(gè)c:\java\classdir條目,需要加載的類是hello.Hello.class,在加載這個(gè)類的時(shí)候,虛擬機(jī)會(huì)查找c:\java\classdir\hello\目錄,如果Hello.class在這個(gè)目錄中,虛擬機(jī)就可以找到。如果這個(gè)類不在這個(gè)目錄中,同時(shí)也不在任何一個(gè)其它c(diǎn)lasspath中,那么虛擬機(jī)會(huì)拋出一個(gè)ClassNotFoundException。虛擬機(jī)查找類的路徑順序虛擬機(jī)尋找類文件所使用路徑的順序:首先自動(dòng)搜索jre/lib和jre/lib/ext目錄下的rt.jar和其他的jar文件。然后搜索當(dāng)前目錄。最后依次搜索-classpath中說明的路徑。注:查找文件時(shí)使用以包名為相對(duì)路徑的文件名。例如importhello.Hello對(duì)于當(dāng)前目錄來說就是查找hello\Hello.class文件。Classpath的順序和類版本沖突Java虛擬機(jī)在加載類的時(shí)候查找classpath是有順序的,如果在classpath中有多個(gè)條目都有同一個(gè)名稱的類,那么在較前位置的類會(huì)被加載,后面的會(huì)被忽略。這種按照順序的類加載可能會(huì)導(dǎo)致類的版本沖突。很多時(shí)候如果不注意這一點(diǎn),可能會(huì)導(dǎo)致奇怪的異常。編譯器如何定位類編譯器在采用與虛擬機(jī)同樣的查找文件方式之外,還要多做一些事情:確定對(duì)象所屬的確切類。如果源代碼中使用了一個(gè)對(duì)象,而沒有明確指出類所在的包,那么編譯器要檢查所有import語句確定類所在的包。如果發(fā)現(xiàn)兩個(gè)包中都有同名的類,則報(bào)告編譯錯(cuò)誤。檢查源文件的是否有更改。編譯器找到類(.class)文件后,還要找到源文件(.java),并比較兩個(gè)文件的最后更新時(shí)間。若源文件比類文件新,則要重新編譯源文件生成類文件。編譯器查找路徑與虛擬機(jī)查找路徑的區(qū)別:編譯器總是查找當(dāng)前目錄。而虛擬機(jī)只有在類路徑中包含當(dāng)前目錄(.)的情況下才查找當(dāng)前目錄。如果沒有設(shè)置類路徑,缺省的類路徑中包含當(dāng)前目錄。這就是說,使用javaHello等價(jià)于java-cp.Hello,搜索當(dāng)前目錄下是否有Hello.class文件;但是java–cphelloHello則只搜索.\hello目錄下是否有Hello.class文件,而不搜索當(dāng)前目錄。編譯器只從當(dāng)前目錄下的類開始編譯。如果Hello.java不放在當(dāng)前目錄而是放在classpath目錄,那么javacHello.java將找不到文件。如果Hello.java在當(dāng)前目錄下,而Hello類中用到的其他類放在classpath目錄中,則編譯可以通過。相反,java命令則可以執(zhí)行不在當(dāng)前目錄下的類。設(shè)置CLASSPATH變量Java和javac命令都有-classpath選項(xiàng),但是如果每次使用都需要設(shè)置類路徑,會(huì)非常冗長(zhǎng)麻煩。因此,Java提供了另外一種選擇,設(shè)置CLASSPATH環(huán)境變量。Win95/98/ME下:編輯autoexec.bat文件,添加一行
SETCLASSPATH=c:\java\classdir;. (注意不要落了分號(hào)后面表示當(dāng)前目錄的點(diǎn)號(hào),=號(hào)兩邊不要有空格。)WinNT/2000/XP下:控制面板系統(tǒng)高級(jí)環(huán)境變量,在用戶環(huán)境變量或者系統(tǒng)環(huán)境變量中添加一項(xiàng),變量名稱為CLASSPATH,值為.;c:\java\classdir;.。UNIX/Linux下,編輯shell的啟動(dòng)文件。若使用CShell,則向位于主目錄的.cshrc文件中添加一行:
setenvCLASSPATH/home/user/classdir:.若使用bash,則向位于主目錄的.bash_profile文件中添加一行:
exportCLASSPATH=/home/user/classdir:.源文件與類文件的存放目錄結(jié)構(gòu):開發(fā)時(shí),源文件(.java)和類文件(.class)一般放在相同目錄下,便于編譯和執(zhí)行。發(fā)布時(shí),如果源代碼不需要保密,那么存放格式和開發(fā)時(shí)相同;如果源代碼不希望給別人看到,或者程序不希望別人改動(dòng),那么按照相同的目錄結(jié)構(gòu)只提供類文件即可。單個(gè)類:若只在某個(gè)特定程序中使用的類,把類放在當(dāng)前目錄下。若需要在多個(gè)程序中共享使用的類,把類放在一個(gè)或多個(gè)特定目錄下,并按包的層次組織文件和目錄層次。例如,可以每個(gè)用戶一個(gè)目錄。將這些保存共享源文件和類文件的目錄添加到CLASSPATH環(huán)境變量中。抽象類抽象類具有以下特性:(1)含有抽象方法的類必須被聲明為抽象類,抽象類必須被繼承,抽象方法必須被實(shí)現(xiàn)。(2)抽象類中不是所有的方法都是抽象方法,可以在抽象類中聲明并實(shí)現(xiàn)方法。(3)抽象類的子類必須實(shí)現(xiàn)父類的所有抽象方法后才能實(shí)例化,否則這個(gè)子類也成為一個(gè)抽象類。(4)抽象類不能實(shí)例化?!纠?.7】Dog類繼承Animal類并實(shí)現(xiàn)抽象方法run()。6.6接口6.6.1接口概念
接口主要作用是可以幫助實(shí)現(xiàn)類似于類的多重繼承的功能。在Java中,出于簡(jiǎn)化程序結(jié)構(gòu)的考慮,不再支持類間的多重繼承而只支持單重繼承,即一個(gè)類至多只能有一個(gè)直接父類。然而在解決實(shí)際問題的過程中,僅僅依靠單重繼承在很多情況下都不能將問題的復(fù)雜性表述完整,需要其他的機(jī)制作為輔助。在Java語言中,接口(Interface)是對(duì)符合接口需求的類的一套規(guī)范。接口與包相似,也是用來組織應(yīng)用中的各類并調(diào)節(jié)它們的相互關(guān)系的一種結(jié)構(gòu),更準(zhǔn)確地說,接口是用來實(shí)現(xiàn)類間多重繼承功能的結(jié)構(gòu)?!?/p>
單繼承性和接口Java的單繼承性使得類結(jié)構(gòu)成為以O(shè)bject類為根的一棵樹。ObjectClass11Class12ClassXX……Java用接口(interface)來獲得多繼承性。接口克服了多繼承性帶來的一些問題。錄音機(jī)U盤Mp3播放器相機(jī)數(shù)碼相機(jī)Object類Object類是Java中所有類的超類。單繼承性帶來的好處:Object類定義了類應(yīng)該提供的一些基本功能,幾個(gè)重要方法如(自定義的類一般都要覆蓋定義):equals方法:用于測(cè)試一個(gè)對(duì)象的內(nèi)容是否和另一個(gè)對(duì)象相等,注意與兩個(gè)對(duì)象引用相等的區(qū)別。toString方法:將對(duì)象內(nèi)容寫到字符串中,可用于將對(duì)象打印輸出。clone方法:將對(duì)象復(fù)制一份。由于多態(tài)性,可以用Object類型的引用指向所有類型的對(duì)象。因此,許多通用編程成為可能,如動(dòng)態(tài)數(shù)組(ArrayList,Vector)、集合、堆棧、鏈表等等。6.6.2接口聲明Java中聲明接口的語法如下:[public]interface接口名[extends父接口名列表]{//接口體;//常量域聲明[public][static][final]域類型
域名=常量值;//抽象方法聲明[public][abstract][native]返回值
方法名(參數(shù)列表)[throw異常列表];}從上面的語法規(guī)定可以看出,定義接口與定義類非常相似,實(shí)際上完全可以把接口理解成為一種特殊的類,接口是由常量和抽象方法組成的特殊類。
6.6.2接口聲明(1)接口中的屬性都是用final修飾的常量,在這個(gè)類中,所有的成員函數(shù)都是抽象的,也就是說它們都只有說明沒有定義;(2)接口中的方法都是用abstract修飾的抽象方法,在接口中只能給出這些抽象方法的方法名、返回值和參數(shù)列表,而不能定義方法體,即僅僅規(guī)定了一組信息交換、傳輸和處理的“接口”。6.6.2接口的實(shí)現(xiàn)一個(gè)類要實(shí)現(xiàn)某個(gè)或某幾個(gè)接口時(shí),有如下的步驟和注意事項(xiàng):
(1)在類的聲明部分,用implements關(guān)鍵字聲明該類將要實(shí)現(xiàn)哪些接口;(2)如果實(shí)現(xiàn)某接口的類不是abstract的抽象類,則在類的定義部分必須實(shí)現(xiàn)指定接口的所有抽象方法,即為所有抽象方法定義方法體,而且方法頭部分應(yīng)該與接口中的定義完全一致,即有完全相同的返回值和參數(shù)列表;
(3)如果實(shí)現(xiàn)某接口的類是abstract的抽象類,則它可以不實(shí)現(xiàn)該接口所有的方法。(4)一個(gè)類在實(shí)現(xiàn)某接口的抽象方法時(shí),必須使用完全相同的方法頭。(5)接口的抽象方法,其訪問限制符都已指定是public,所以類在實(shí)現(xiàn)方法時(shí),必須顯式地使用public修飾符。接口聲明:用interface關(guān)鍵字,聲明中只指定原型,不直接定義方法的內(nèi)容。實(shí)現(xiàn):類要實(shí)現(xiàn)某個(gè)接口用implements關(guān)鍵字,在類的定義中給出接口中所定義方法的實(shí)際實(shí)現(xiàn)。接口中的方法和變量都是public的。對(duì)于變量,自動(dòng)(且只能)為staticfinal成員變量。一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。interfaceComparable{intcompareTo(Objectother);}classStudentimplementsComparable{privatelongid;publicvoidsetID(longaID){…};publicintcompareTo(ObjectotherObject);{Studentother=(Student)otherObject;if(id<other.id)return–1;if(id>other.id)return1;return0;}}Student類的對(duì)象數(shù)組可以在Arrays中進(jìn)行排序等操作。使用接口接口用于下面一些情況:聲明方法,期望一個(gè)或更多的類來實(shí)現(xiàn)該方法。決定一個(gè)對(duì)象的編程界面,而不揭示類的實(shí)際程序體。捕獲無關(guān)類之間的相似性,而不強(qiáng)迫類關(guān)系?;卣{(diào)功能,如排序(sort)方法需要用到比較(compareTo)方法等。接口與對(duì)象:接口不是類,所以不能用接口創(chuàng)建對(duì)象,即不能用new運(yùn)算符。
x=newComparable(); //錯(cuò)誤可以聲明接口類型的引用,該引用只能指向?qū)崿F(xiàn)了該接口的對(duì)象。一個(gè)使用的例子在Java庫源代碼的Arrays.java文件1144行mergeSort方法。
classStudentimplementsComparable {...} Comparablex; x=newStudent();接口具有以下特性:(1)接口中的常量默認(rèn)為publicstaticfinal,并且也只能是public
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《騰訊微博操作指南》課件
- 甘孜職業(yè)學(xué)院《建筑工程制圖》2023-2024學(xué)年第一學(xué)期期末試卷
- 甘肅政法大學(xué)《有限元分析》2023-2024學(xué)年第一學(xué)期期末試卷
- 《漂亮的熱帶魚》課件
- 《小兒發(fā)熱的護(hù)理》課件
- 三年級(jí)數(shù)學(xué)上冊(cè)七年月日看日歷說課稿北師大版
- 三年級(jí)科學(xué)上冊(cè)第1單元水7混合與分離教案2教科版
- 2022年-2023年三支一扶之公共基礎(chǔ)知識(shí)基礎(chǔ)試題庫和答案要點(diǎn)
- 小學(xué)生優(yōu)教課件下載
- 考評(píng)員培訓(xùn)課件
- 做賬實(shí)操-科學(xué)研究和技術(shù)服務(wù)業(yè)的賬務(wù)處理示例
- 2025年人教版歷史八上期末復(fù)習(xí)-全冊(cè)重難點(diǎn)知識(shí)
- 山東省濱州市2023-2024學(xué)年高一上學(xué)期1月期末考試 政治 含答案
- 儀控技術(shù)手冊(cè)-自控專業(yè)工程設(shè)計(jì)用典型條件表
- 法務(wù)崗位招聘筆試題及解答(某大型國(guó)企)2025年
- 《慶澳門回歸盼祖國(guó)統(tǒng)一》主題班會(huì)教案
- 洗衣房工作人員崗位職責(zé)培訓(xùn)
- 廣東省深圳市光明區(qū)2022-2023學(xué)年五年級(jí)上學(xué)期數(shù)學(xué)期末試卷(含答案)
- XX小區(qū)春節(jié)燈光布置方案
- 《華為銷售人員培訓(xùn)》課件
- 《廣西壯族自治區(qū)房屋建筑和市政工程施工招標(biāo)文件范本(2023年版)》
評(píng)論
0/150
提交評(píng)論