资源预览内容
第1页 / 共129页
第2页 / 共129页
第3页 / 共129页
第4页 / 共129页
第5页 / 共129页
第6页 / 共129页
第7页 / 共129页
第8页 / 共129页
第9页 / 共129页
第10页 / 共129页
亲,该文档总共129页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
,第5章 继承与多态,5.1 继承 5.2 多态 5.3 重载 5.4 抽象方法与抽象类 5.5 接口 练习题,5.1 继 承 5.1.1 继承的概念 面向对象程序设计里的继承机制模仿了现实中IS-A关系(层次关系),如车辆可以分为机动车和非机动车,它们拥有车辆的共同特征,同时又有自己特有的属性;机动车又可以分为内燃机车和电车,它们拥有机动车的共同特征,同时又有自己特有的属性;也就是说,各种各样的车辆形成了图5-1所示的一棵继承树。,图5-1 车辆的继承树,面向对象程序中继承实际上是存在于两个类之间的一种关系。当一个类A能够获取另一个类B中所有非私有成员的定义作为自己的一部分或全部时,就称这两个类之间具有继承关系。被继承的类B称为父类或超类,继承了父类或超类的属性和方法的类A称为子类。 一个父类可以同时拥有多个子类,这时这个父类实际上是所有子类公共属性和公共方法的集合,而每一子类则是父类的特殊化,是在父类的基础之上对公共属性和方法在功能、内涵方面的扩展和延伸。使用继承具有以下好处:降低了代码编写中的冗余度,更好地实现了代码复用的功能,从而提高了程序编写的效率;由于降低了代码的冗余度,使得程序在维护时就变得非常方便。,例如,要实现对各种电话卡的管理,声明定义相应的卡类,可以通过两种方法来实现:第一种方法是对每一种卡都分别独立定义一个类,如图5-2所示;第二种方法是使用继承来定义相应的类,各种电话卡类的层次结构、属性和方法如图5-3所示。,图5-2 独立定义的电话卡类,图5-3 使用继承定义的电话卡类,从图5-2中可以看出,第一种方法定义的各类是相互独立的,所以每一个电话卡类中都定义自己的属性或方法。这样的定义显得非常冗余,大量地重复一些共有的成员,同时,后期的维护工作也非常繁琐。例如程序需要修改“剩余金额”这个属性的数据类型,那么将对所有具有“剩余金额”属性的类都要进行修改,工作量是非常大的,而且还容易因疏漏而出现错误。图5-3所示的第二种实现方案使用了继承的思想来定义类,就能很好地解决第一种方法中出现的问题。它是仅在抽象的电话卡父类中定义剩余金额属性,其他类则从它那里继承。因此第二种方案相对于第一种方案来说,代码量要少若干倍。同时,当公共属性发生修改时,第二种方案只需要在父类中修改一次即可,不但维护的工作量大大减少,而且也避免了在第一种方案中可能出现的修改遗漏。,使用面向对象的这种继承关系也很符合人们的日常思维模式。电话卡分为无卡号、有卡号两大类,无卡号的电话卡可以具体分为磁卡、IC卡等,有卡号的电话卡可具体分为IP电话卡和200电话卡等。其中,电话卡这个抽象概念对应的电话卡类是所有其他类的父类,它是所有电话卡的公共属性的集合。这些公共属性包括卡中剩余金额等静态的属性,以及拨打电话、查询余额等动态的行为属性。将电话卡具体化、特殊化,就分别派生出两个子类:无卡号电话卡和有卡号电话卡。这两个子类一方面继承了父类电话卡的所有属性(包括属性与方法),即它们也拥有剩余金额、拨打电话、查询余额等属性和方法;另一方面它们又根据自己对原有的父类概念的明确和限定,专门定义了适用于本类特殊需要的特殊属性,如对于所有的有卡号电话卡,应该有卡号、密码等属性和登录交换机的行为,这些属性对无卡号电话卡是不适合的。从有卡号电话卡到IP电话卡和200电话卡的继承遵循完全相同的原则。使用继承的主要优点是,可使程序结构清晰,降低编码和维护的工作量。,在面向对象的继承特性中,还有一个关于单重继承和多重继承的概念。所谓单重继承,是指任何一个类都只有一个单一的父类;而多重继承是指一个类可以有一个以上的父类,它从多个父类中继承属性和方法。采用单重继承的程序结构比较简单,是单纯的树状结构,掌握、控制起来相对容易;而支持多重继承的程序,其结构则是复杂的网状,设计、实现都比较复杂。但现实世界中,事物之间的关系往往是复杂的网状结构,用多重继承描述起来比较自然。C+是支持多重继承的面向对象编程语言,而Java语言仅支持单重继承,但Java可以通过接口来间接实现多重继承。,5.1.2 继承的实现 1继承的定义 Java中通过关键字extends来定义两个类之间的继承关系,extends后面的是父类,新定义的是子类。一般形式为: 类修饰符 class 子类名 extends 父类名 如果父类和子类不在同一个包中,则需要使用“import”语句来引入父类所在的包。,2类成员的继承 继承能够使子类拥有父类的非私有属性和方法,而不需要在子类的类定义时重新定义父类的这些属性和方法。子类继承了父类属性,表示子类在被创建时另开辟新的空间来存储从父类继承而来的属性,其初始值应该是父类中该属性的初值。从这以后,父类属性与子类属性分别独立存放,互不干扰。对于父类的私有成员,子类不能继承。,【例5-1】继承示例一。 public class ExtendTest1 public static void main(String args) ParentClass parent=new ParentClass(); SonClass son=new SonClass(); SonClass1 son1=new SonClass1(); /三句执行的效果一样,son、son1继承了父类中的parentmethod() parent.parentmethod(); son.parentmethod(); son1.parentmethod(); ,class ParentClass private int x; /声明私有成员 protected int y; /声明保护成员 int z;/声明缺省成员 public int w; /声明公有成员 public void parentmethod() System.out.println(“call parent class function: parentmethod()“); ,class SonClass extends ParentClass /派生类中不能继承父类中的私有成员,其他成员均可继承(非私有成员) public void displayprivate() /引用父类中的私有成员 /System.out.println(“X=“+x); public void displayprotected() /引用父类中的保护成员 System.out.println(“Y=“+y); public void displaypublic() /引用父类中的公有成员 System.out.println(“W=“+w); public void displaydefault() /引用父类中的默认成员 System.out.println(“Z=“+z); class SonClass1 extends ParentClass ,程序运行结果为: call parent class function: parentmethod() call parent class function: parentmethod() call parent class function: parentmethod(),【例5-2】继承示例二。 public class ExtendTest2 public static void main(String args) ParentClass parent=new ParentClass(1); SonClass son=new SonClass(3); System.out.println(“调用父类getX():“+parent.getX(); System.out.println(“调用子类songetX():“+son.songetX(); /调用子类自身定义的方法 System.out.println(“通过子类调用getX():“+son.getX(); /调用从父类处继承过来的方法 /后两句的输出相同,说明子类继承了父类中的getX()方法,访问子类中的x,x从父类中继承而来,parent.setX(11); /修改父类的x,子类x不变 System.out.println(“调用父类getX():“+parent.getX(); System.out.println(“调用子类songetX():“+son.songetX(); System.out.println(“通过子类调用getX():“+son.getX(); class ParentClass ParentClass() x=0; ,ParentClass(int a) x=a; protected int x; /声明保护成员 public void setX(int a) x=a; public int getX() return(x); ,class SonClass extends ParentClass SonClass(int a) x=a; public void sonsetX(int a) x=a; /在子类中并不限于只使用父类的方法,也可以在子类中定义自己的方法 public int songetX() return(x); ,程序运行结果为: 调用父类getX():1 调用子类songetX():3 通过子类调用getX():3 调用父类getX():11 调用子类songetX():3 通过子类调用getX():3,3构造函数的继承 构造函数是与类同名的特殊方法,在创建一个对象的同时系统将会调用该类的构造函数完成对象的初始化工作。所以,在实现继承关系时,系统对它的处理和其他一般方法就有所不同了。子类可以继承父类的构造函数,构造函数的继承遵循下列原则: (1) 子类只继承父类的默认(缺省)构造函数,即无形参构造函数。如果父类没有默认构造函数,那子类不能从父类继承到任何构造函数。,(2) 子类从父类处继承来的父类默认构造函数,不能成为子类的默认构造函数。 (3) 在创建对象时,先调用父类默认构造函数对对象进行初始化,然后调用子类自身自己定义的构造函数。 (4) 如果子类想调用父类的非默认构造函数,则必须使用super来实现。 (5) 子类必须调用父类的构造函数。可以通过系统自动调用父类的默认构造函数,如果父类没有默认构造函数时,子类构造函数必须通过super调用父类的构造函数。,【例5-3】构造函数继承示例。 public class ConstructorExtends public static void main(String args) ParentClass parent=new ParentClass(1); SonClass son1=new SonClass(1); SonClass son2=new SonClass(“abc“,2); class ParentClass ,/在类的继承中,如果父类中没有默认构造函数,那子类必须通过super来调用父类的其他构造 /函数初始
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号