第4章继承、接口和内部类继承、超类和子类抽象类和接口内部类Class类4.1继承、超类和子类继承是一种由已有的类创建新类的机制。运用继承,可以先创建一个通用类,它定义一组相关属性的一般特性。该类可以具体类继承,每个具体类都增加一些自己特有的东西。被继承的类叫超类(superclass),继承超类的类叫子类(subclass)。子类不能继承父类中访问权限为private的成员变量和方法。子类可以重写父类的方法,及命名与父类同名的成员变量。Java不支持多重继承,即一个类从多个超类派生的能力。通过继承可实现代码复用。Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的4.1.1子类继承一个类,要用extends关键字指定要继承的父类。创建子类的一般格式为:classSubClass[extendsSuperClass]{…}classStudentsextendsPeople{}4.1.2子类的继承子类通过隐藏父类的成员变量和重写父类的方法,可以把父类的状态和行为改变为自身的状态和行为。例如:classSuperClass{intx;…voidsetX(){x=0;}…}classSubClassextendsSuperClass{intx;…voidsetX(){x=5;}…}隐藏了父类同名成员变量重写了父类的同名同参方法思考:1、在定义一个类中,当局部变量和成员变量同名时,会怎么样?如何使用同名成员变量?2、在定义一个类中,多次定义同名不同参的方法时,会怎么样?在这些方法中,如何使用前面被定义的同名不同参的方法?2、在定义一个子类时,当子类定义了和父类同名的成员变量和方法时,会怎么样?如何使用父类中同名的成员变量和方法?方法重写及重写规则子类定义了和父类同名、同参、同返回类型的方法,称为子类重写了父类的方法规则:子方法的名称、参数类型及顺序、返回类型必须与重写方法相同不能降低的重写方法的访问性不能比重写方法抛出更多的异常4.1.3super关键字关键字super表示父类对象。在子类中使用super做前缀可以引用被子类隐藏的父类变量或被子类重写的父类方法子类不能继承父类的构造方法,但在子类可用super关键字调用父类的构造方法。此时必须是方法体中第一条语句。1.Super的使用方法访问父类被隐藏的成员变量super.variable;调用父类中被重写的方法super.Method([paramlist]);在子类的构造方法中,调用父类的构造方法super([paramlist]);P86【例4-2】P87【例4-3】利用supers操作父类的构造方法。若子类在定义构造方法中,没有使用super调用父类的某个构造方法,则系统默认有“super()”,即调用父类不带参数的构造方法,产生一个调用父类构造函数的数据链。最终发生的是父类构造函数(可能几个)将在链中的任何子类构造函数前执行。Java规定如果在一个类中含有一个或多个构造方法,系统不提供默认的构造方法(不含参数的构造方法),所以当在父类中定义了多个构造方法时,应考虑包括一个不带参数的构造方法,以防止子类省略super关键字时出现错误。对象的上转型对象假设B类是A类子类或间接子类,当我们用子类B创建一个对象,并把这个对象的引用赋值给A类的对象时:Aa;Bb=newB();a=b;称这个A类对象:a,是子类对象b的上转型对象Aa=newB();对象的上转型对象的实体是子类负责创建的,但上转型对象会失去原子类对象的一些属性和功能。对象的上转型对象子类对象子类新增的变量子类新增的方法子类重写或继承的变量子类重写或继承的方法如果子类重写了父类的某个方法后,对象的上转型对象调用这个方法时,一定是调用了子类重写的方法。可以将对象的上转型对象再强制转换到原子类对象(下转换对象),这时,该子类对象又具备了子类所有属性和功能。class动物{voidcry(){}}class狗extends动物{voidcry(){System.out.println(汪汪.....);}}class猫extends动物{voidcry(){System.out.println(喵喵.....);}}classExample{publicstaticvoidmain(Stringargs[]){动物dongwu;if(Math.random()=0.5){dongwu=new狗();dongwu.cry();}else{dongwu=new猫();ongwu.cry();}}}多态性父类的某个方法被多个子类重写时,相同的调用(上转型对象的调用)可以产生各自不同的行为(结果)。动物dongwu1,dongwu2;dongwu1=new狗();dongwu2=new猫()dongwu1.cry();dongwu2.cry();instanceof操作符用于判断一个实例对象是否属于一个类,即若某个实例对象是某个类或其子类的实例时,返回真格式:对象instanceof类publicvoidmethod(Employeee){if(einstanceofManager){//Managem=(Manage)e;…}elseif(einstanceofContractor){//Contractorc=(Contractor)e;…}else{//temporaryemployee}}在你接收父类的一个引用时,你可以通过使用Instanceof运算符判定该对象实际上是你所要的子类,并可以用向下类型转换该引用的办法来恢复对象的全部功能如果不用instanceof做测试,就会有类型转换失败的危险4.2抽象类和接口Java语言中,用abstract关键字修饰的类叫做抽象类用abstract关键字来修饰的方法叫做抽象方法含有抽象方法的类必须定义为抽象类格式如下:abstractclassabstractclass{…}abstractreturnTypeabstractMethod([paramlist])为什么要定义抽象类?——图形类4.2.1抽象类抽象类不能使用new方法进行实例化AbstractClassa1=newAbstratClass();AbstractClassa1=newSubClass();抽象方法没有方法体当一个方法为抽象方法时,此这个方法必须被子类的方法所重写,否则子类也是抽象的。抽象类中不一定包含抽象方法,但是包含抽象方法的类一定要被声明为抽象类。构造方法、静态方法不能声明为抽象的×√需要注意的是:抽象类不能用final来修饰,即一个类不能既是最终类又是抽象类。abstract不能与private、static、final并列修饰同一个方法。P89【例4-5】定义抽象类Animal,从抽象类派生子类Horse和Dog,实现父类的抽象方法。4.2.2接口接口是抽象类的一种,只包含常量和方法的定义,没有变量,且方法都是抽象方法。为什么要用接口?:通过接口定义不相关类的相同行为,而无需考虑这些类之间的关系。通过接口了解对象的交互界面,而无需了解对象所对应的类是如何实现的。请问?那些地方需要收费功能?公交车、出租车、飞机、电影院、公园等为什么不用抽象类定义?考虑机动车抽象类定义收费功能,合理吗?机动车有轿车、卡车、客车、拖拉机等4.2.3接口的定义接口的定义包括接口声明和接口体。接口声明的格式如下:[public]interfaceinterfaceName[extendsSuperInterfaceList]{…}和类不同的是:一个接口可有多个父接口,用逗号隔开接口体包括常量定义和方法定义常量被实现该接口的多个类共享,具有public,final,static的属性typeNAME=value;方法体具有public和abstract属性returnTypemethodName([paramlist]);4.2.4接口的实现在类的声明中用implements子句来表示一个类实现某个接口,在类体中可以使用接口中定义的常量,但必须实现接口中定义的所有方法。P91【例4-6】接口实现案例4.3内部类内部类是在一个类的内部定义的类,其作为外部类的一个成员,并且依附于外部类而存在内部类根据定义的位置不同,可以作为某个类的成员(成员内部类),也可以在一个语句块的内部定义(局部内部类),还可以在表达式内部定义(匿名内部类)。//成员内部类:与成员变量和方法并列publicclassOutClass{成员变量、成员方法定义;classInnerClass{…}}作为外部类的一个成员存在,与外部类的属性、方法并列//局部内部类:方法中定义publicclassOutClass{…publicvoidmothod(){if(true){…classInnerClass{…}}}publicclassOuter2{privateintouter_i=10;voidtest(){Innerin=newInner();in.display();}classInner{privateintinner_i=5;voiddisplay(){System.out.println((outer_i+inner_i));}}publicstaticvoidmain(Stringargs[]){Outer2outer=newOuter2();outer.test();}}为什么使用内部类?当第一个类(外)中的程序代码要用到第二个类(内)的实例对象,而第二个类(内)中的程序代码又要访问第一个类(外)中的成员,将第二个类(内)作为第一个类(外)的内部类,程序代码更容易实现,这种情况在实际应用中非常多。1、成员内部类类似于成员属性和方法,可用protected和private修饰可以用static修饰吗?在成员内部类中可以定义和外部类同名的成员变量和方法吗?若可以如何区分?//Outer6.javapublicclassOuter6{privatestaticinti=1;privateintj=10;publicvoidouter_f1(){}classInner{intj=100;voidinner_f1(){System.out.println(i);System.out.println(j);System.out.println(this.j);System.out.println(Outer6.this.j);outer_f1();}}//外部类的非静态方法访问成员内部类publicvoidouter_f2(){Innerinner=newInner();inner.inner_f1();}}//InnerTest.javapublicclassInnerTest{publicstaticvoidmain(String[]args){Outer6out=newOuter6();Outer6.Inneroutin=out.newInner();outin.inner_f1();}}Outer6.java编译后生成两个单独文件:Outer6.class和Outer7$Inner.class2、局部内部类与局部变量类似,局部内部类不能有访问控制符;它可以访问当前代码块内的用final修饰的常量,和外部类所有的成员不能在局部代码块之外建立内部类实例//Outer7.javapublicclassOuter7{privateints=100;publicvoidf(finalintk){inti=1;//变量内部类不能访问finalintj=10;//常量内部类可以访问classInner{ints=300;Inner(intk){inner_f(k);}voidinner_f(intk){System.out.println(j);System.out.println(s);S