您好,欢迎访问三七文档
第5章继承和多态继承和多态性是面向对象程序设计的重要内容。继承机制是实现软件构件复用的一种强有力的手段。多态性是面向对象编程的重要特性,是继承产生的结果。Java语言很好的体现了继承和多态性两大特性。本章将讨论用Java语言实现继承和多态性,具体将介绍继承概念、继承的实现、抽象类的作用、方法的覆盖以及用接口实现多继承。5.1继承继承是面向对象程序设计的三大概念之一,是面向对象程序的重要概念,它使程序代码复用成为可能。假设已经定义和实现类DigitalProduction(代表数码产品),需要定义一个新的应用类MobilePhone(代表手机)。由于手机是数码产品的一种,所以没有必要对类DigitalProduction中属于数码产品特征重新书写代码,只需要继承类DigitalProduction的属性特征即可。这样,类MobilePhone通过继承获得了类DigitalProduction的数据和方法。由于类MobilePhone也具有自身的特征,如“进网许可号”,可以为这些异于其他数码产品的特征定义成员数据和成员方法。这样,MobilePhone继承于DigitalProduction,又具有新的属性特征。图5-1可以表示了两个类之间的继承关系。图5-1MobilePhone继承DigitalProduction从这个意义上来说,继承是指一个新的类继承原有类的基本特性,并增加新的特性。通俗地说,新的类与原有类之间体现了一种“is-a”关系。只要类和类之间存在的继承关系,这种扩展可以一直延续下去,它体现出类的层次结构。例如,而类MobilePhone继承于类DigitalProduction。而类IntelligentMobile(代表智能手机)继承于类MobilePhone。继承可以分成两大类型:单继承和多继承。单继承是一个类只能从一个类派生而来,即只有一个父类。多继承是一个类可以从多个类派生而来,可以有多个父类。Java语言只支持单继承,不支持多继承。5.1.1父类和子类Java语言中,继承实际上是一个类扩展一个已有的类。被扩展的类是父类,而扩展类是子类。子类继承了父类的类成员,并可以定义自己的独特的属性成员。通常体现了子类和父类之间是派生与被派生的关系。所以,有时称父类为基类,而子类称为派生类。Java语言也体现出类的层次结构。Java语言中定义类java.lang.Object,它是所有类的父类。其他类无论是直接还是间接都是继承了Object类,具有Object类的属性,如在第4章中说明的finalize()方法。比如,Java语言提供的类java.lang.String直接继承于类java.lang.Object,而javax.swing.JOptionPane则是间接继承于java.lang.Object,JOptionPane类具体继承情况见图5-2。同样,用户自定义类也是直接或间接继承于java.lang.Object类,具体实现见5.1.2。图5-2javax.swing.JOptionPane的继承示意5.1.2继承的实现Java语言中是通过关键字extends来实现单继承的。简单的实现格式如下:class子类名extends父类名{类体}有一点要注意,如果在格式中没有通过extends关键字来标明父类名,这并不是意味着该类无父类,相反,它表示该类是java.lang.Object的子类。例5.1类继承的示例。publicclassBaseClass{//定义一个类BaseClasspublicintintValue;//定义成员数据intValue;publicBaseClass(){intValue=3;System.out.println(BaseClass定义);}publicvoidshowBaseMessage(){System.out.println(BaseClass信息);}}publicclassDerivedClassextendsBaseClass{//定义类DerivedClasspublicDerivedClass(){System.out.println(DerivedClass定义);}publicvoidshowDerivedMessage(){System.out.println(继承而来的数据:+intValue);//引用继承的成员数据intValueSystem.out.println(DerivedClass信息);}publicstaticvoidmain(Stringargs[]){DerivedClassdc=newDerivedClass();dc.showBaseMessage();//引用继承的成员方法showBaseMessagedc.showDerivedMessage();System.exit(0);}}图5-3例5.1的运行结果例5.1定义了两个类BaseClass和DerivedClass,其中DerivedClass是BaseClass的子类,BaseClass是DerivedClass的父类。它们之间通过定义DerivedClass中增加extends子句来实现继承关系。尽管类BaseClass的定义没有用关键字extends来说明父类,但实际上它是隐性3的定义为java.lang.Object的子类。这样,java.lang.Object、BaseClass和DerivedClass之间就构成了继承关系链。创建一个子类如DerivedClass的对象时,会从上向下调用Object-BaseClass-DerivedClass继承链的默认构造方法。从图5-3中可以看出,创建一个DerivedClass的对象之前先调用了父类BaseClass的默认构造方法。注意,如果在继承链中存在某个父类没有定义默认构造方法,会产生编译错误。不过,尽管子类可以继承父类的成员数据和成员方法,但并不意味着子类可以完全继承父类的全部属性。如果将例5.1中类BaseClass的公有(public)成员数据intValue改成私有(private)成员数据,再编译类Derived,会发现程序出现编译错误。这是由于类成员的访问控制限制了类成员的可见性。父类的私有成员是不能被子类所继承。就好比孩子继承了父亲的部分特征,而不是全部特征。5.2抽象类在现实生活中,可以发现这样的现象:许多实物抽象出成为一个共同的类别,如“交通工具”,但是“交通工具”并直接对应着实际存在的类别如卡车、自行车、三轮车等。又如“动物”,并不特指具体的某个实际存在,它只是哺乳动物、两栖动物等以有机物为食物,可运动生物的统称。“交通工具”、“动物”等这些只是作为一个抽象概念存在,对一组固定实现的抽象描述,并不对应具体的概念。因此,在面向对象程序设计中,可以将这些抽象描述定义为抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。由于抽象类对一组具体实现的抽象性描述,所以抽象体是不能修改的。通常抽象类不具备实际功能,只用来派生子类。5.2.1抽象方法Java语言中,用关键字abstract修饰的方法为抽象方法。语法格式形如:abstract返回值类型方法名([形式参数]);例如:abstractvoidshowMessage();抽象方法只有方法头没有方法体,即只提供方法的规格说明,没有具体的实现。抽象方法只能出现在抽象类(见5.2.2)和接口(见5.4)中,其他类中定义会产生编译错误。有两点必须注意:1)final关键字不能修饰抽象方法。这是因为final是不可修改的方法是最终的方法,而抽象方法没有方法体,能被派生类进行覆盖;2)static是不能修饰抽象方法的。静态方法占据固定内存空间,而抽象方法根本就不可能运行,不会加载到内存中。所以,static关键字不能修饰抽象方法。5.2.2抽象类抽象类是用关键字abstract修饰的类为抽象类。语法格式形如:abstractclass抽象类名{类体}抽象类只是具体实体的抽象描述,是不可以实例化对象。尽管抽象类定义构造方法是没有语法错误,但是没有实际意义。抽象类中可以定义非抽象方法,也可以定义抽象方法。抽象方法在它的派生子类中可以覆盖,来实现具体功能。抽象类派生出的子类,必须对抽象类中的抽象方法重写。如果没有对抽象方法重写,该子类须定义为抽象类,否则产生编译错误。与抽象方法类似,如果一个类要定义为抽象类,就不能用关键字static或关键字final修饰,原因同抽象方法,在这里就不再说明。例5.2抽象类的示例。publicabstractclassAbstractClassExample{//AbstractClassExample.javapublicabstractvoidshowMessage();//定义抽象方法showMessage()publicvoidprintClassName(Stringname){//定义非抽象方法printClassName(String)System.out.println(name);}}publicclassDerivedAbstractClassextendsAbstractClassExample{//DerivedAbstractClass.javapublicDerivedAbstractClass(){System.out.println(DerivedAbstractClassDefinition);}publicvoidshowMessage(){//覆盖父类的showMessage()方法;System.out.println(DerivedAbstractClassMessage);}publicstaticvoidmain(Stringargs[]){DerivedAbstractClassdac=newDerivedAbstractClass();dac.showMessage();dac.printClassName(Classnameis:DerivedAbstractClass);//引用继承来的方法System.exit(0);}}图5-4例5.2的运行结果5.3多态性多态性是面向对象程序设计的重要特性,它是继承机制产生的结果。所以,继承是多态的前提。面向对象程序设计中,严格的来说多态性是运行绑定机制。这种机制是实现将方法名绑定到方法具体实现代码。通俗地理解就是“一个名字,多种形式”。实际上,最常见的多态的是符号“+”,有如下的表示式:6+5//实现整数相加3+5.0f//将3隐性转化为float类型,实现单精度数字的相加IAMCHINESE+4//实现字符串连接操作。同一个“+”有多种含义:整数相加、单精度数字相加、双精度数字相加、字符串连接等操作。当然,上述的表达式3+5.0f中数据类型的隐性的转换也是一种多态的体现。又如,在第三章讨论的对象的finalize()方法也是多态。因为,不同类型的对象都有finalize()方法,但根据要求的不同,可以赋予finalize()方法不同代码内容,产生不同的功能。另外,类的构造方法也是多态的一种形式。在创建对象时,根据参数的性质来选择构造方法初始化对象。根据消息选择响应方法的角度来看,多态分成两种形式:编译多态(Compile-timePolymorphism)和运行多态(Run-timePolymorphism)。在编译时期根据信息选择响应的方法称为编译多态。Java语言中,实现编译多态性主要有方法的重载。运行的多态是在程序运行5的时才可以确认响应的方法。通常运行的多态是通过继承机制引起的。从实际编程的角度来看,Java语言实现多态性有三种形式:1)方法的重载;2)通过继承机制而产生的方法覆盖;3)通过接口实现的方法覆盖(见5.4.2)。在本节中对方法的重载和方法的覆盖做一个详细的介绍。5.3.1方法的重载重载(Overloading)实质上就是在一个类内用一个标识符定义不同的方法或符号运算的方法名或符号名。J
本文标题:第5章继承和多态
链接地址:https://www.777doc.com/doc-2196563 .html