第五章继承与接口_第1页
第五章继承与接口_第2页
第五章继承与接口_第3页
第五章继承与接口_第4页
第五章继承与接口_第5页
已阅读5页,还剩81页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第五章继承与接口 5.1子类与父类5.2子类的继承性5.3子类对象的构造过程5.4成员变量的隐藏和方法的重写5.5abstract类和abstract方法5.6final关键字5.7对象的上转型对象5.8继承与多态5.9super关键字5.10接口5.11总结Person类的定义classPerson{

} Stringname; intage; voidgetInfo() { }Student类的定义 Stringname; intage; Stringgrade; voidgetInfo() { }classStudent{}classStudent{ Stringname; intage; Stringgrade; voidgetInfo() { }}classPerson{ Stringname; intage; voidgetInfo() { }}Person类与Student类的比较继承

继承是一种由已有的类创建新类的机制。

利用继承,我们可以先创建一个共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。

由继承而得到的类称为子类(派生类),被继承的类称为父类(基类或超类)。

Java不支持多重继承(子类只能有一个父类)。5.1子类与父类在类的声明中,通过使用关键字extends来创建一个类的子类。如:

classStudentsextendsPeople{

……}

如果一个类的声明中没有使用extends关键字,这个类被系统默认为是Object的子类。Object是包java.lang中的类。5.2子类的继承性类有可以有两种重要的成员:成员变量和方法。子类的成员中有一部分是子类自己声明定义的,另一部分是从它的父类继承的。所谓子类继承父类的成员变量作为自己的一个成员变量,就好象它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法直接操作。所谓子类继承父类的方法作为子类中的一个方法,就象它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法直接调用。5.2.1子类和父类在同一包中

如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法。classFather{privateintmoney;intweight;intgetWeight(){returnweight;}protectedvoidsetWeight(intw){weight=w;}}例子1classSonextendsFather{Stringhand;publicvoidsetHand(Stringhand){this.hand=hand;}StringgetHand(){returnhand;}}

publicclassExample5_1{publicstaticvoidmain(Stringargs[]){Sonson=newSon();Grandsongrandson=newGrandson();son.setWeight(67);son.setHand("一双大手");grandson.setWeight(25);grandson.setHand("一双小手");grandson.setFoot("一双小脚");System.out.println("儿子重量:"+son.getWeight());System.out.println("孙子重量:"+grandson.getWeight());System.out.println("儿子的手:"+son.getHand());System.out.println("孙子的手:"+grandson.getHand());System.out.println("孙子的脚:"+grandson.getFoot());}}5.2.2子类和父类不在同一包中

如果子类和父类不在同一个包中,那么,子类继承了父类的protected、public成员变量做为子类的成员变量,并且继承了父类的protected、public方法为子类的方法,但不能继承父类的友好变量和友好方法。同一个类中同一个包中不同包中的子类不同包中的非子类private★友好★★protected★★★public★★★★

当用子类的构造方法创建一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,也就是说,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。5.3子类对象的造型过程

子类对象的内存示意图引用子类继承的成员子类对象子类声明的成员子类未继承的成员classA{privateintx;voidsetX(intx){this.x=x;}intgetX(){returnx;}}classBextendsA{doubley=12;publicvoidsetY(inty){//this.y=y+x;非法,子类没有继承x}publicdoublegetY(){returny;}}例子2publicclassE{publicstaticvoidmain(Stringargs[]){Bb=newB();b.setX(888);System.out.println("子类对象未继承的x的值是:"+b.getX());b.y=12.678;System.out.println("子类对象的实例变量y的值是:"+b.getY());}}5.4成员变量的隐藏和方法的重写子类也可以隐藏继承的成员变量。对于子类可以从父类继承的成员变量,只要子类中定义的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量。子类通过方法的重写可以隐藏继承的方法,方法重写是指:子类中定义一个方法,并且这个方法的名字、返回类型、参数个数和类型与从父类继承的方法完全相同。

方法重载:classArea{floatgetArea(floatr){return3.14f*r*r;}doublegetArea(floatx,inty){returnx*y}floatgetArea(intx,floaty);{returnx*y;}doublegetArea(floatx,floaty,floatz){return(x*x+y*y+z*z)*2.0;}}5.4成员变量的隐藏和方法的重写

对于子类创建的一个对象,如果子类重写了父类的方法,则运行时系统调用子类重写的方法,如果子类继承了父类的方法(未重写),那么子类创建的对象也可以调用这个方法,只不过方法产生的行为和父类的相同而已。classA{floatf(intx,inty){returnx+y;}publicvoidg(){System.out.println("Iamastudent");}}classBextendsA{floatf(intx,inty){returnx*y;}}例子3publicclassE{publicstaticvoidmain(Stringargs[]){Bb=newB();floatresult=b.f(3,5);//b调用重写的方法

System.out.println(result);b.g();//b调用继承的方法

}}

classA{protectedfloatf(floatx,floaty){returnx-y;}}classBextendsA//非法,因为降低了访问级别{floatf(flaotx,floaty){returnx+y;}}classCextendsA{publicfloatf(flaotx,floaty)//合法,没有降低访问级别

{returnx*y;}}

重写父类的方法时,不可以降低方法的访问权限。5.5abstract类和abstract方法

用关键字abstract修饰的类或方法称为abstract类(抽象类)或abstract方法(抽象方法)。定义形式:

abstractclassA{

…}

第一,abstract类中可以有abstract方法和普通的类相比,abstract类可以有abstract方法。对于abstract方法,只允许声明,不允许实现,而且不允许使用final修饰abstract方法。abstractclassA{abstractintmin(intx,inty);intmax(intx,inty){returnx>y?x:y;}}

第二,abstract类不能用new运算创建对象对于abstract类,我们不能使用new运算符创建该类的对象,需产生其子类,由子类创建对象,如果一个类是abstract类的子类,它必须具体实现父类的abstract方法,这就是为什么不允许使用final修饰abstract方法的原因。例子4abstractclassA{abstractintsum(intx,inty);intsub(intx,inty){returnx-y;}}classBextendsA{intsum(intx,inty)//子类必须重写父类的sum方法

{returnx+y;}}publicclassE{publicstaticvoidmain(Stringargs[]){Bb=newB();intsum=b.sum(30,20);//调用重写的方法

intsub=b.sub(30,20);//调用继承的方法

System.out.println("sum="+sum);System.out.println("sum="+sub);}}

一个abstract类只关心它的子类是否具有某种功能,并不关心功能的具体行为,功能的具体行为由子类负责实现,抽象类中的抽象方法可以强制子类必须给出这些方法的具体实现。例5:abstractclass机动车{abstractvoid启动();abstractvoid加速();abstractvoid刹车();}class手动档轿车extends机动车//不是abstract类{void启动(){System.out.println("踏下离合器,换到一挡");System.out.println("然后慢慢抬起离合器");}void加速(){System.out.println("踩油门");}void刹车(){System.out.println("踏下离合器,踏下刹车板");System.out.println("然后将挡位换到一挡");}}class自动档轿车extends机动车{void启动(){System.out.println("使用前进挡");System.out.println("然后轻踩油门");}void加速(){System.out.println("踩油门");}void刹车(){System.out.println("踏下刹车板");}}publicclassE{publicstaticvoidmain(Stringargs[]){

手动档轿车car1=new手动档轿车();

自动档轿车car2=new自动档轿车();car1.启动();car1.加速();car1.刹车();car2.启动();car2.加速();car2.刹车();}}5.6final关键字

final关键字可以修饰类、修饰成员变量和方法中的参数以及修饰方法。5.6.1final类

final类不能被继承,即不能有子类。如果一个成员变量被修饰为final的,就是常量,常量必须赋给初值,而且不能再发生变化。如果方法的参数被修饰为final的,该参数的值不能被改变。如果一个方法被修饰为final方法,则这个方法不能被重写。

如:finalclassA{

…}A就是一个final类。有时候是出于安全性的考虑,将一些类修饰为final类。例如Java提供的String类,它对于编译器和解释器的正常运行有很重要的作用,对它不能轻易改变,因此它被修饰为final类。classA{//finaldoublePI;非法,因为没有给常量指定值

finaldoublePI=3.1415926;//PI是常量

publicdoublegetArea(finaldoubler){//r=89;非法,因为不允许再改变r的值

returnPI*r*r;}publicfinalvoidspeak(){System.out.println("您好");}}例子6

classBextendsA{/*非法,不能重写speak方法

publicvoidspeak(){System.out.println("你好");}*/}publicclassE{publicstaticvoidmain(Stringargs[]){Bb=newB();System.out.println("面积:"+b.getArea(100));b.speak();//调用继承的方法

}}5.7对象的上转型对象我们经常说”老虎是哺乳动物”,”狗是哺乳动物”等。若哺乳类是老虎类的父类,这样说当然正确,但当你说老虎是哺乳动物时,老虎将失掉老虎独有的属性和功能。那么,继承关系可以扼要的表示为:“新class是旧class的一种形式。”例:假设A类是B类的父类,当我们用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如

Aa;或Aa;a=newB();Bb=newB();a=b;

称这个父类对象是子类对象的上转型对象。

对象的上转型对象的实体是子类负责创建的,但上转型对象会失去原对象的一些属性和功能。上转型对象具有如下特点:1、上转型对象不能操作子类新增的成员变量,失掉了这部分属性;不能使用子类新增的方法,失掉了一些功能。2、上转型对象可以操作子类继承或隐藏的成员变量,也可以使用子类继承的或重写的方法。3、如果子类重写了父类的某个方法后,当对象的上转对象调用这个方法时一定是调用了这个重写的方法,因为程序在运行时知道,这个上转对象的实体是子类创建的,只不过损失了一些功能而已。可以将对象的上转型对象再强制转换到一个子类对象,这时该子类对象又具备了子类所给的所有属性和功能。不可以将父类创建的对象的引用赋值给子类声明的对象,就像不能说”哺乳动物是老虎”。对象的上转型对象对象新增的变量新增的方法继承或隐藏的变量继承或重写的方法class类人猿{doublem=12.58;voidcrySpeak(Strings){System.out.println(s);}}classPeopleextends类人猿{charm='A';intn=60;voidcomputer(inta,intb){intc=a+b;System.out.println(a+"加"+b+"等于"+c);}voidcrySpeak(Strings){System.out.println(m+"**"+s+"**"+m);}}例子7classE{publicstaticvoidmain(Stringargs[]){Peoplewang=newPeople();

类人猿monkey=wang;//monkey是wang对象的上转型对象。

monkey.crySpeak("Ilovethisgame");//等同于wang调用crySpeak方法

//monkey.n=100;//非法,n是子类新增的成员变量

//puter(12,19);//非法,computer是子类新增的功能

System.out.println(monkey.m);//操作隐藏的m,不等同于wang.mPeoplezhang=(People)monkey;//把上转型对象强制转化为子类的对象

puter(55,33);//zhang是子类的对象

zhang.m='T';//操作子类声明的成员的变量mSystem.out.println(zhang.m);}}5.8继承与多态性

多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为。当一个类有很多子类时,并且这些子类都重写了父类中的某个方法。那么当我们把子类创建的对象的引用放到一个父类的对象中时,就得到了该对象的一个上转型对象,那么这个上转的对象在调用这个方法时就可能具有多种形态。例8class动物

{voidcry(){}}class狗extends动物

{voidcry(){System.out.println("汪汪.....");}}class猫extends动物

{voidcry(){System.out.println("喵喵.....");}}classE{publicstaticvoidmain(Stringargs[]){

动物dongwu;dongwu=new狗();dongwu.cry();dongwu=new猫();dongwu.cry();}}

使用多态进行程序设计的核心技术之一是使用上转型对象,可将abstract类声明对象作为其子类的转型对象,这个上转型对象就可以调用子类重写的方法。5.8.2多态的使用多态的使用abstract类

abstractintf();abstractintg();子类1

intf(){…}intg(){…}子类2

intf(){…}intg(){…}子类的上转型对象obj所在的类

Obj.f();Obj.g();Geometry.javapublicabstractclassGeometry{publicabstractdoublegetArea();}Lader.javapublicclassLaderextendsGeometry{doublea,b,h;Lader(doublea,doubleb,doubleh){this.a=a;this.b=b;this.h=h;}publicdoublegetArea(){return((1/2.0)*(a+b)*h);}}例子9Circle.javapublicclassCircleextendsGeometry{doubler;Circle(doubler){this.r=r;}publicdoublegetArea(){return(3.14*r*r);}}Cone.javapublicclassCone{Geometrybottom;doubleheight;Cone(Geometrybottom,doubleheight){this.bottom=bottom;this.height=height;}voidchangeBottom(Geometrybottom){this.bottom=bottom;}publicdoublegetVolume(){return(bottom.getArea()*height)/3.0;}}Example5_9.javapublicclassExample5_9{publicstaticvoidmain(Stringargs[]){Conezui;Geometrytuxing;tuxing=newLader(2.0,7.0,10.7);System.out.println("梯形的面积"+tuxing.getArea());zui=newCone(tuxing,30);System.out.println("梯形底的锥的体积"+zui.getVolume());tuxing=newCircle(10);System.out.println("半径是10的圆的面积"+tuxing.getArea());zui.changeBottom(tuxing);System.out.println("圆形底的锥的体积"+zui.getVolume());}}5.9super关键字子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中的第一条语句。

如果我们在子类中想使用被子类隐藏了的父类的成员变量或方法就可以使用关键字super。比如:super.x、super.play(),就是被子类隐藏的父类的成员变量x和方法play()。5.9.1使用super调用父类的构造方法子类不能直接继承父类的构造方法,因此子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中的第一条语句。例:classStudent{intnumber;Stringname;Student(intnumber,Stringname){this.number=number;=name;System.out.println("Iam"+name+"mynumberis"+number);}}classStudent{intnumber;Stringname;Student(){}Student(intnumber,Stringname){this.number=number;=name;System.out.println("Iam"+name+"mynumberis"+number);}}classUniverStudentextendsStudent{boolean婚否;UniverStudent(intnumber,Stringname,booleanb){super(number,name);

婚否=b;System.out.println("婚否="+婚否);}}publicclassExample5_10{publicstaticvoidmain(Stringargs[]){UniverStudentzhang=newUniverStudent(9901,"和晓林",false);}}

需要注意的是:在子类的构造方法中,如果没有显示地使用super关键字调用父类的某个构造方法,那么这时系统已经默认地在子类的构造方法中加载了一个:

super();

语句,即调用父类的不带参数的构造方法。如果父类没有提供不带参数的构造方法,就会出现错误。5.9.2使用super操作被隐藏的成员变量和方法如果我们在子类中想使用被子类隐藏了的父类的成员变量或方法就可以使用关键字super。比如super.x、super.play(),就是被子类隐藏的父类的成员变量x和方法play()。例11:classSum{intn;doublef(){doublesum=0;for(inti=1;i<=n;i++)sum=sum+i;returnsum;}}classAverageextendsSum{doublen;//子类继承的int型变量n被隐藏

doublef(){doublec;super.n=(int)n;//子类double型变量n进行int转换运算赋值给隐藏的int型变量nc=super.f();returnc+n;}doubleg(){doublec;c=super.f();returnc-n;}}publicclassExample5_11{publicstaticvoidmain(Stringargs[]){Averageaver=newAverage();aver.n=100;floatresult_1=aver.f();floatresult_2=aver.g();System.out.println("result_1="+result_1);System.out.println("result_2="+result_2);}}5.10接口Java不支持多继承性,即一个类只能有一个父类。单继承性使得Java简单,易于管理程序。为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口。5.10.1接口的声明与使用使用关键字interface来定义一个接口。接口的定义和类的定义很相似,分为接口的声明和接口体。1.接口的声明与使用

interface接口的名字

2.接口体接口体中只进行方法的声明,不许提供方法的实现,所以,方法的定义没有方法体,且用分号“;”结尾。如:interfacePrintable{finalintMAX=100;voidadd();floatsum(floatx,floaty);}3.接口的使用

一个类通过使用关键字implements声明自己使用一个或多个接口。如果使用多个接口,用逗号隔开接口名。如:

classAimplementsPrintable,AddableclassDogextendsAnimalimplementsEatable,Sleepable

如果一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。需要注意的是在类中实现接口的方法时,方法的名字、返回类型、参数个数及类型必须与接口中的完全一致。

特别要注意的是接口中的方法被默认是public的,所以类在实现接口方法时一定要用public来修饰。如果接口的方法的返回类型如果不是void的,那么在类中实现该接口方法时,方法体至少要有一个return语句。如果是void型,方法体除了两个大括号外,也可以没有任何语句。

Java为我们提供的接口都在相应的包中,通过引入包可以使用Java提供的接口。也可以自己定义接口,一个java源文件就是由类和接口组成的。例子12interfaceComputable{intMAX=100;intf(intx);}classChinaimplementsComputable{intnumber;publicintf(intx)//不要忘记public关键字

{intsum=0;for(inti=1;i<=x;i++){sum=sum+i;}returnsum;}}classJapanimplementsComputable{intnumber;publicintf(intx){return66+x;}}publicclassExample5_12{publicstaticvoidmain(Stringargs[]){Chinazhang;Japanhenlu;zhang=newChina();henlu=newJapan();zhang.number=991898+Computable.MAX;henlu.number=941448+Computable.MAX;System.out.println("number:"+zhang.number+"求和"+zhang.f(100));System.out.println("number:"+henlu.number+"求和"+henlu.f(100));}}

注:如果一个类声明实现一个接口,但没有实现接口中的所有方法,那么这个类必须是abstract类。interfaceComputable{intMAX=100;voidspeak(Strings);intf(intx);}abstractclassChinaimplementsComputable{publicintf(intx){intsum=0;for(inti=1;i<=x;i++){sum=sum+i;}returnsum;}}5.10.2理解接口

接口的思想在于它可以增加很多类都需要实现的功能,使用相同的接口类不一定有继承关系。同一个类也可以实现多个接口。接口只关心功能,并不关心功能的具体实现。例子13interface收费{publicvoid收取费用();}interface调节温度{publicvoidcontrolTemperature();}class公共汽车implements收费{publicvoid收取费用(){System.out.println(“公共汽车:一元/张,不计算公里数");}}class出租车implements收费,调节温度{publicvoid收取费用(){System.out.println(“出租车:1.60元/公里,起价3公里");}publicvoidcontrolTemperature(){System.out.println("安装了Hair空调");}}class电影院implements收费,调节温度{publicvoid收取费用(){System.out.println("电影院:门票,十元/张");}publicvoidcontrolTemperature(){System.out.println("安装了中央空调");}}classExample5_13{publicstaticvoidmain(Stringargs[]){公共汽车七路=new公共汽车();

出租车天宇=new出租车();

电影院红星=new电影院();

七路.收取费用();

天宇.收取费用();

红星.收取费用();

天宇.controlTemperature();

红星.controlTemperature();}}5.10.3接口回调接口回调是指可以把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量中。那么该接口变量就可以调用被类实现的接口中的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法。例14interfaceShowMessage{void显示商标(Strings);}classTVimplementsShowMessage{publicvoid显示商标(Strings){System.out.println(s);}}classPCimplementsShowMessage{publicvoid显示商标(Strings){System.out.println(s);}}publicclassExample5_14{publicstaticvoidmain(Stringargs[]){ShowMessagesm;sm=newTV();sm.显示商标("长城牌电视机");sm=newPC();sm.显示商标("联想奔月5008PC机");}}扩展例子1interfaceComputerable{publicdouble求面积();}class梯形implementsComputerable{doublea,b,h;

梯形(doublea,doubleb,doubleh){this.a=a;this.b=b;this.h=h;}publicdouble求面积(){return((1/2.0)*(a+b)*h);}}class圆形implementsComputerable{doubler;

圆形(doubler){this.r=r;}publicdouble求面积(){return(3.14*r*r);}}class堆{Computerable底;double高;

堆(Computerable底,double高){this.底=底;this.高=高;}void换底(Computerable底){this.底=底;}publicdouble求体积(){return(底.求面积()*高)/3.0;}}publicclassExample{publicstaticvoidmain(Stringargs[]){堆zui;Computerablebottom;bottom=new梯形(2.0,7.0,10.7);System.out.println("梯形的面积"+bottom.求面积());zui=new堆(bottom,30);System.out.println(“梯形底的堆的体积”+zui.求体积());bottom=new圆形(10);System.out.println("半径是10的圆的面积"+bottom.

求面积());zui.换底(bottom);System.out.println(“圆形底的堆的体积”+zui.求体积());}}5.10.4接口与多态

当把实现接口的类的实例的引用赋值给接口变量后,该接口变量可以回调类实现的接口方法。接口产生的多态是指不同的类在实现同一个接口时可能具有不同的实现方式,那么接口变量在回调接口方法时就可能具有多种形态。多态的使用interface

abstractintf();abstractintg();类A

intf(){…}intg(){…}类B

intf(){…}intg(){…}interface变量a所在的类例子15Geometry.javapublicinterfaceGeometry//接口{publicabstractdoublegetArea();}Lader.javapublicclassLaderimplementsGeometry

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论