《第4章继承多态与接口.ppt》由会员分享,可在线阅读,更多相关《第4章继承多态与接口.ppt(53页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第4章继承多态与接口 Still waters run deep.流静水深流静水深,人静心深人静心深 Where there is life,there is hope。有生命必有希望。有生命必有希望继承的概念继承的概念父类父类或超类。实际上是所有或超类。实际上是所有子类的公共域和公共方法的子类的公共域和公共方法的集合集合子类子类,父类的特殊化,父类的特殊化,是对公是对公共域和方法在功能、内涵方共域和方法在功能、内涵方面的扩展和延伸面的扩展和延伸,祖先类的,祖先类的所有成员均将成为子类拥有所有成员均将成为子类拥有的的“财富财富”Object类类是所有类的祖先是所有类的祖先Java继承的实现继承
2、的实现classStudent/未使用继承未使用继承privateStringaddress;/籍贯籍贯privateStringname;/姓名姓名privateintage;/年龄年龄Stringno;/学号学号publicStudent(Stringname1,intage1)name=name1;age=age1;/其它其它Java继承的实现继承的实现classStudentextendsPersonStringno;/学号学号/其它其它只有no属性是新加入的,其它属性在Person类中均存在继承关系中构造方法的作用继承关系中构造方法的作用(1)当当子类未定义构造方法子类未定义构造方法
3、时时,创建对象时将无条创建对象时将无条件地调用父类的无参构造方法;件地调用父类的无参构造方法;(2)对于父类的含参数构造方法对于父类的含参数构造方法,子类可以在自己子类可以在自己构造方法中使用关键字构造方法中使用关键字super来调用它来调用它,但但super调调用语句必须是子类构造方法中的第一个可执行语句;用语句必须是子类构造方法中的第一个可执行语句;(3)子类在自己定义构造方法中子类在自己定义构造方法中如果没有用如果没有用super明确调用父类的构造方法,则在创建对象时明确调用父类的构造方法,则在创建对象时,将自将自动先执行父类的无参构造方法动先执行父类的无参构造方法,然后再执行自己定然后
4、再执行自己定义的构造方法。义的构造方法。以下程序在编译时将出错,为什么?以下程序在编译时将出错,为什么?classparentStringmy;publicparent(Stringx)my=x;publicclasssubclassextendsparent例例4-1类的继承中构造方法的调用测试类的继承中构造方法的调用测试classPerson/Person类类privateStringaddress;/籍贯籍贯privateStringname;/姓名姓名privateintage;/年龄年龄publicStringgetName()/获取人名获取人名returnname;publicPe
5、rson(Stringname1,Stringaddress1,intage1)name=name1;address=address1;age=age1;publicPerson()name=无名氏无名氏;例例4-1类的继承中构造方法的调用测试类的继承中构造方法的调用测试publicclassStudentextendsPersonStringno;/学号学号publicStudent(Stringname1,Stringaddress1,intage1,Stringno1)super(name1,address1,age1);no=no1;publicstaticvoidmain(Strin
6、ga)Studentx=newStudent(张三张三,江西江西,25,20012541);System.out.println(name=+x.getName();System.out.println(no=+x.no);/Studenty=newStudent();不能使用,子类无该构造方法不能使用,子类无该构造方法子类中将隐藏父类的同名变量子类中将隐藏父类的同名变量classparentinta=3;intm=2;publicclasssubclassextendsparentinta=4;intb=1;publicstaticvoidmain(Stringa)subclassmy=ne
7、wsubclass();System.out.println(a=+my.a+,b=+my.b+,m=+my.m);4.2.1公共访问控制符公共访问控制符public作为类的修饰符,将类声明为公共类作为类的修饰符,将类声明为公共类,表明表明它可以被所有的其它类所访问和引用它可以被所有的其它类所访问和引用作为类的成员的访问修饰符,表明在其他作为类的成员的访问修饰符,表明在其他类中可以无限制地访问该成员。类中可以无限制地访问该成员。要要真正做到类成员可以在任何地方访问,真正做到类成员可以在任何地方访问,在进行类设计时必须同时满足两点在进行类设计时必须同时满足两点:首先首先类被定义为类被定义为pub
8、lic,其次,类的成员被定义为其次,类的成员被定义为public。4.2.2缺省访问控制符缺省访问控制符没有给出访问控制符情形没有给出访问控制符情形该类只能被同一个包中的类访问和引用该类只能被同一个包中的类访问和引用4.2.3私有访问控制符私有访问控制符private用用private修饰的域或方法只能被该类自身所访问修饰的域或方法只能被该类自身所访问例例4-3测试对私有成员的访问测试对私有成员的访问classMyclassprivateinta;/私有变量私有变量voiddisplay()System.out.println(a);publicclasstestpublicstaticvoi
9、dmain(Stringarg)Myclassmy=newMyclass();my.a=5;my.display();4.2.4保护访问控制符保护访问控制符protected用用protected修饰的成员可以在三种类中所引用修饰的成员可以在三种类中所引用:该类本身;该类本身;与它在同一个包中的其它类;与它在同一个包中的其它类;在其它包中的该类的子类。在其它包中的该类的子类。例例4-4测试包的访问控制的一个简单程序测试包的访问控制的一个简单程序文件文件1:PackageData.java(该文件存放在(该文件存放在sub子目录下)子目录下)packagesub;publicclassPacka
10、geDataprotectedstaticintnumber=1;文件文件2:Mytest.javaimportsub.*;publicclassMytestpublicstaticvoidmain(Stringargs)System.out.println(result=+PackageData.number);各类访问控制符的作用可以归纳为表各类访问控制符的作用可以归纳为表3-1可直接访问修饰同一类中同一包中不同包的子类中其他privateYes默认YesYesprotectedYesYesYespublicYesYesYesYes4.3.1方法的重载方法的重载(例)例)publiccla
11、ssAprotectedvoidtest(intx,inty)System.out.println(test(int,int):+x+y);protectedvoidtest(intx)System.out.println(test(int):+x);protectedvoidtest(Stringstr)System.out.println(test(String):+str);publicstaticvoidmain(Stringargs)Aa1=newA();a1.test(hello);a1.test(5,4);4.3.1方法的重载方法的重载通过形式参数表的差异来区分通过形式参数表的差
12、异来区分方法调用的匹配原则方法调用的匹配原则:1)精确匹配精确匹配2)自动转换匹配自动转换匹配基本类型转换基本类型转换对象引用转换对象引用转换例例4-5方法调用的匹配测试方法调用的匹配测试publicclassAprotectedintx=0;protectedvoidtest(intx)System.out.println(test(int):+x);protectedvoidtest(Objectobj)System.out.println(test(Object):+obj);protectedvoidtest(Stringstr)System.out.println(test(Stri
13、ng):+str);publicstaticvoidmain(Stringargs)Aa1=newA();a1.test(hello);a1.test(5);【思考思考】如果在以上程序中加上如下方法如果在以上程序中加上如下方法,并将并将test(intx)方方法注释掉法注释掉,则调用则调用test(5)如何如何?protectedvoidtest(longx)System.out.println(test(long):+x);如果是以下情形如果是以下情形,调用调用test(6.3)?protectedvoidtest(floatx)System.out.println(test(float):
14、+x);4.3.2方法的覆盖方法的覆盖以下类以下类B定义的方法中,方法覆盖如何?定义的方法中,方法覆盖如何?classBextendsAprotectedvoidtest(intx)System.out.println(inB.test(int):+x);protectedvoidtest(Stringx,inty)System.out.println(inB.test(String,int):+x+,+y);【思考思考】通过子类通过子类B的对象可调用多少的对象可调用多少test方法?方法?关于方法覆盖有以下问题值得注意:关于方法覆盖有以下问题值得注意:方法名、参数列表、返回类型完全相同方法名
15、、参数列表、返回类型完全相同才会产生方才会产生方法覆盖;法覆盖;如果返回类型不一样编译将报错。如果返回类型不一样编译将报错。方法覆盖不能改变方法的方法覆盖不能改变方法的静态与非静态属性静态与非静态属性。子类中。子类中不能将父类非静态方法定义为静态方法,反之也一样。不能将父类非静态方法定义为静态方法,反之也一样。不允许子类中不允许子类中方法的访问修饰符方法的访问修饰符比父类有更多的限制。比父类有更多的限制。例如:子类不能将父类的例如:子类不能将父类的public方法定义为方法定义为protected方法。但可以将父类的方法。但可以将父类的private方法在子类中重新定义方法在子类中重新定义为为
16、public方法方法.final方法不能被覆盖。方法不能被覆盖。this-出现在类的实例方法或构造方法中,用出现在类的实例方法或构造方法中,用来代表使用该方法的对象来代表使用该方法的对象(1)把当前对象的引用作为参数传递给另一个方法。)把当前对象的引用作为参数传递给另一个方法。如:如:obj.f(this)(2)可以调用当前对象的其它方法或访问当前对象的实例变量。)可以调用当前对象的其它方法或访问当前对象的实例变量。如:如:this.g();(3)使用)使用this可以区分当前作用域中同名的不同变量。可以区分当前作用域中同名的不同变量。Stringx;publicTest(Stringx,in
17、ta)this.x=x;(4)一个构造方法中调用另一个构造方法。)一个构造方法中调用另一个构造方法。publicTest(finalintx)this(x,0);(1)用用Super访问超类的变量或方法访问超类的变量或方法classparentinta=3;voidf()a=a+1;publicclasssubclassextendsparentinta=6;voidf()super.f();a=a+super.a-3;(2)调用超类的构造方法)调用超类的构造方法publicclassgraduate_studentextendsStudentDateenterDate;/入校时间入校时间pu
18、blicgraduate_student(Stringname,intage,Dated)super(name,age);enterDate=d;如果有如果有super(),必须放在构造方法的第一条语句,必须放在构造方法的第一条语句子类中调用方法的查找过程以及子类中调用方法的查找过程以及this和和super的用法的用法【思考】如果graduate_student中无toString()方法,则this.toString()将会出现什么情况?4.5final修饰符修饰符final作为类修饰符作为类修饰符-最终类最终类(不能有子类)(不能有子类)用用final修饰方法修饰方法-不能被子类重新定义
19、不能被子类重新定义用用final定义常量定义常量-只能赋值一次只能赋值一次注意:注意:如果将引用类型的变量标记为如果将引用类型的变量标记为final,那么该那么该变量固定指向一个对象,但可以改变对象内的属变量固定指向一个对象,但可以改变对象内的属性值。性值。例例4-7常量赋值测试常量赋值测试publicfinalclasstestpublicstaticinttotalNumber=5;publicfinalintid;publicintweight;publictest(intweight)id=totalNumber+;this.weight=weight;publicstaticvoid
20、main(Stringargs)finaltestt=newtest(5);t=newtest(4);t.weight=t.weight+2;4.6.1抽象类的定义抽象类的定义abstractclass类名称类名称成员变量;成员变量;方法()方法()/一般方法一般方法abstract方法();方法();/抽象方法抽象方法在抽象类中可以包含一般方法和抽象方法。在抽象类中可以包含一般方法和抽象方法。所有的抽象方法必须存在于抽象类中。所有的抽象方法必须存在于抽象类中。抽象类表示的是一个抽象概念,不能被实例化为抽象类表示的是一个抽象概念,不能被实例化为对象。对象。4.6.2抽象类的实现抽象类的实现ab
21、stractclassAnimal/抽象类抽象类Stringname;abstractpublicintgetLeg();/抽象方法抽象方法classDogextendsAnimalintleg=4;publicDog(Stringn)name=n;publicintgetLeg()returnleg;4.6.2抽象类的实现(续抽象类的实现(续1)classFishextendsAnimalpublicFish(Stringn)name=n;publicintgetLeg()return0;4.6.2抽象类的实现(续抽象类的实现(续2)publicclasstestpublicstaticvo
22、idmain(Stringargs)Animala=newAnimal3;a0=newDog(dog-A);a1=newFish(“fish-A);a2=newDog(dog-B);for(inti=0;i3;i+)System.out.println(ai.name+has+ai.getLeg()+legs);4.7.1接口定义接口定义publicinterface接口名接口名extends父接口名列表父接口名列表publicstaticfinal域类型域类型域名域名=常量值常量值;publicabstractnative返回值返回值方法名方法名(参数列参数列表表)throw异常列表异常列表
23、;声明接口可给出访问控制符;声明接口可给出访问控制符;一个接口还可以继承多个父接口一个接口还可以继承多个父接口,父接口间用逗号分隔。,父接口间用逗号分隔。系统默认接口中所有系统默认接口中所有属性属性的修饰都是的修饰都是publicstaticfinal;系统默认接口中所有系统默认接口中所有方法方法的修饰都是的修饰都是publicabstract。4.7.1接口定义举例接口定义举例interfaceShapevoiddraw();/用于绘制形状用于绘制形状doublearea();/用于求面积用于求面积4.7.2接口的实现接口的实现abstractpublicclassRectangleimpl
24、ementsShapeprivatedoublex,y,w,h;publicRectangle(doublex,doubley,doublew,doubleh)this.x=x;this.y=y;this.w=w;this.h=h;publicdoublearea()returnw*h;有关接口的实现有关接口的实现,要注意以下问题要注意以下问题一个类可以实现多个接口。接口间用逗号分隔;一个类可以实现多个接口。接口间用逗号分隔;如果实现某接口的类不是抽象类如果实现某接口的类不是抽象类,则在类的定义部则在类的定义部分分必须实现指定接口的所有抽象方法必须实现指定接口的所有抽象方法;一个类在实现某接口
25、的抽象方法时一个类在实现某接口的抽象方法时,必须使用完全必须使用完全相同的方法头;相同的方法头;接口的抽象方法的访问限制符默认为接口的抽象方法的访问限制符默认为public,在实在实现时要在方法头中显式地加上现时要在方法头中显式地加上public修饰修饰。例例4-9接口应用举例接口应用举例interfaceStartStopvoidstart();voidstop();classConferenceimplementsStartStoppublicvoidstart()System.out.println(Starttheconference.);publicvoidstop()System.
26、out.println(Stoptheconference.);例例4-9接口应用举例接口应用举例(续(续1)classCarimplementsStartStoppublicvoidstart()System.out.println(Insertkeyinignitionandturn.);publicvoidstop()System.out.println(Turnkeyinignitionandremove.);例例4-9接口应用举例接口应用举例(续(续2)publicclassTestInterfacepublicstaticvoidmain(Stringargs)StartStops
27、s=newCar(),newConference();for(inti=0;iss.length;i+)ssi.start();ssi.stop();二义性问题二义性问题interfaceFrobfloatv=2.0f;/接口定义接口定义classParentintv=3;/父类定义父类定义classTestextendsParentimplementsFrobpublicstaticvoidmain(Stringargs)newTest().printV();voidprintV()System.out.println(super.v+Frob.v)/2);例例4-10一个简单例子一个简单例
28、子publicclassOuterOneprivateintx=3;InnerOneino=newInnerOne();publicclassInnerOne/内嵌类内嵌类privateinty=5;publicvoidinnerMethod()System.out.println(yis+y);publicvoidinnerMethod2()System.out.println(x2is+x);创建内嵌类创建内嵌类的对象的对象作为作为外部类的一外部类的一个属性成员个属性成员例例4-10一个简单例子(续)一个简单例子(续)publicvoidOuterMethod()System.out.pr
29、intln(xis+x);ino.innerMethod();ino.innerMethod2();publicstaticvoidmain(Stringarg)OuterOnemy=newOuterOne();my.OuterMethod();调用内嵌调用内嵌类的方法类的方法有关说明有关说明内嵌类经过编译后产生的字节码文件名为:内嵌类经过编译后产生的字节码文件名为:OuterOne$InnerOne.class在内嵌类中可以访问外层类的成员在内嵌类中可以访问外层类的成员内嵌类可以使用访问控制符内嵌类可以使用访问控制符public、protected、private修饰修饰在外层类中访问内嵌类
30、的方法在外层类中访问内嵌类的方法方法方法1:在外层类的:在外层类的成员定义中创建内嵌类的对象成员定义中创建内嵌类的对象,例如:例如:InnerOneino=newInnerOne();然后,在外层类中通过该成员变量然后,在外层类中通过该成员变量ino访问内嵌类访问内嵌类的方法的方法方法方法2:在程序的某个:在程序的某个方法体中创建内嵌类的对象方法体中创建内嵌类的对象,然后通过该对象访问内嵌类的成员,如:然后通过该对象访问内嵌类的成员,如:publicvoidaccessInner()InneroneanInner=newInnerone();anInner.innerMethod();在在ma
31、in方法中间接创建内嵌类的对象方法中间接创建内嵌类的对象在在main方法中,要创建内嵌类的对象必须先创建方法中,要创建内嵌类的对象必须先创建外层类对象,然后通过外层类对象创建内嵌类对外层类对象,然后通过外层类对象创建内嵌类对象。例如:象。例如:publicstaticvoidmain(Stringarg)OuterOne.InnerOnei=newOuterOne().newInnerOne();i.innerMethod();在内嵌类中使用在内嵌类中使用this-在内嵌类中,在内嵌类中,this指内嵌类的对指内嵌类的对象,要访问外层类的当前对象须加上外层类名作前缀象,要访问外层类的当前对象须
32、加上外层类名作前缀publicclassAprivateintx=3;publicclassB/内嵌类内嵌类privateintx=5;publicvoidM(intx)System.out.println(x=+x);System.out.println(this.x=+this.x);System.out.println(A.this.x=+A.this.x);/内嵌类结束内嵌类结束内嵌类对象内嵌类对象外部类的当前对象外部类的当前对象例例4-12静态内嵌类举例静态内嵌类举例publicclassOutertwoprivatestaticintx=3;privateinty=5;public
33、staticclassInnertwo/静态内嵌类静态内嵌类publicstaticvoidMethod()System.out.println(xis+x);publicvoidMethod2()System.out.println(xis+x);/内嵌类结束内嵌类结束publicstaticvoidmain(Stringarg)Outertwo.Innertwo.Method();newOutertwo.Innertwo().Method2();方法中的内嵌类方法中的内嵌类(例(例4-13)publicclassOuterTwoprivateintx=3;publicvoidOuterMe
34、thod(intm)finalintn=x+2;classInnerTwo/方法内的内嵌类方法内的内嵌类privateinty=5;publicvoidinnerMethod()System.out.println(yis+y);System.out.println(nis+n);System.out.println(xis+x);/内嵌类结束内嵌类结束只能访问外部只能访问外部方法中的常量方法中的常量(带(带final修饰)修饰)方法中的内嵌类(例方法中的内嵌类(例4-13续)续)InnerTwoin2=newInnerTwo();in2.innerMethod();publicstaticv
35、oidmain(Stringarg)OuterTwomy=newOuterTwo();my.OuterMethod(8);匿名内嵌类匿名内嵌类interfacesamplevoidtestMethod();publicclassAnonymousInnervoidOuterMethod()newsample()publicvoidtestMethod()System.out.println(justtest);.testMethod();/调用内嵌类中定义的方法调用内嵌类中定义的方法-字节码文件为字节码文件为AnonymousInner$1.class。如果有更多的。如果有更多的匿名内嵌类将按
36、递增序号命名匿名内嵌类将按递增序号命名由接口派生匿由接口派生匿名内嵌类,根名内嵌类,根据该内嵌类创据该内嵌类创建对象建对象4.9.1对象引用赋值转换对象引用赋值转换Objectx=newApple();Fruitm=newOrange();Applex=newFruit();4.9.1对象引用赋值转换对象引用赋值转换在赋值时允许的转换归纳如下:在赋值时允许的转换归纳如下:接口类型可转换为父接口或接口类型可转换为父接口或Object类;类;类对象可以转换为父类或该类实现了的接口类型;类对象可以转换为父类或该类实现了的接口类型;数组可以转换为数组可以转换为Object,也可转换为,也可转换为Clo
37、neable或或Serializable接口。数组还可转换为一个新数组,但旧接口。数组还可转换为一个新数组,但旧数组的元素类型必须能够允许转换为新类型方可。数组的元素类型必须能够允许转换为新类型方可。4.9.2对象引用强制转换对象引用强制转换将父类引用赋值给子类变量时要进行强制转换,将父类引用赋值给子类变量时要进行强制转换,这种这种强制转换强制转换在编译时总是认可的,但运行时的在编译时总是认可的,但运行时的情况取决于对象的值情况取决于对象的值Friutx;Appley;Orangem,n;n=newOrange();x=n;m=(Orange)x;y=(Apple)x;作业作业1)利用随机函数定义利用随机函数定义10对对(x,y)值,由此创建的值,由此创建的Point类实例存入一个数组中,按与原点(类实例存入一个数组中,按与原点(0,0)的距离由小到大的顺序输出所有的点及到原点的的距离由小到大的顺序输出所有的点及到原点的距离。距离。2)编写一个三角形类,能根据)编写一个三角形类,能根据3个实数构造三角形个实数构造三角形对象,如果三个实数不满足三角形的条件,则自对象,如果三个实数不满足三角形的条件,则自动构造以最小值为边的等边三角形。输入任意三动构造以最小值为边的等边三角形。输入任意三个数,求构造的三角形面积。个数,求构造的三角形面积。
限制150内