您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > chapter06多态性.
第六章多态性学习目标理解多态性的概念理解继承层次结构中对象间的关系区分抽象类与具体类抽象类和抽象方法的声明和使用接口的声明和实现final类和final方法嵌套类的概念和使用基本数据类型的包装类6.1多态性概念和实例封装性通过合并各种特征与行为,封装技术可创建出新的数据类型。通过对具体实施细节的隐藏,可将接口与实施细节分离,使所有细节成为“private”(私有)。继承可将一个对象当作它自己的类型或者它自己的基础类型对待。6.1多态性概念和实例多态性(Polymorphism)在超类中定义的属性或行为,被子类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在超类及其各个子类中具有不同的语义。6.1多态性概念和实例对象既能以其自身类型的形式被使用,又能被视为其基础类型而被使用。这称为向上转型。classNote{privateintvalue;privateNote(intval){value=val;}publicstaticfinalNotemiddleC=newNote(0),cSharp=newNote(1),cFlat=newNote(2);}//Etc.classInstrument{publicvoidplay(Noten){System.out.println(Instrument.play());}}classWindextendsInstrument{//Redefineinterfacemethod:publicvoidplay(Noten){System.out.println(Wind.play());}}publicclassMusic{publicstaticvoidtune(Instrumenti){i.play(Note.middleC);}publicstaticvoidmain(String[]args){Windflute=newWind();tune(flute);//Upcasting}}///:~6.1多态性概念和实例其中,方法Music.tune()接收一个Instrument引用,同时也接收从Instrument衍生出来的所有东西。当一个Wind引用传递给tune()的时候,就会出现这种情况。此时没有造型的必要。这样做是可以接受的;Instrument里的接口必须存在于Wind中,因为Wind是从Instrument里继承得到的。。6.1多态性概念和实例为什么要上溯造型这个程序看起来也许显得有些奇怪。为什么所有人都应该有意忘记一个对象的类型呢?进行上溯造型时,就可能产生这方面的疑惑。而且如果让tune()简单地取得一个Wind句柄,将其作为自己的自变量使用,似乎会更加简单、直观得多。但要注意:假如那样做,就需为系统内Instrument的每种类型写一个全新的tune()。假设按照前面的推论,加入Stringed(弦乐)和Brass(铜管)这两种Instrument(乐器)多态:以基本类型视之(函数调用)绑定方法将一个方法调用同一个方法主体连接到一起就称为“绑定”(Binding)。若在程序运行以前执行绑定(由编译器和链接程序,如果有的话),就叫作“早期绑定”。大家以前或许从未听说过这个术语,因为它在任何程序化语言里都是不可能的。C编译器只有一种方法调用,那就是“早期绑定”。上述程序最令人迷惑不解的地方全与早期绑定有关,因为在只有一个Instrument句柄的前提下,编译器不知道具体该调用哪个方法。解决的方法就是“后期绑定”,它意味着绑定在运行期间进行,以对象的类型为基础。后期绑定也叫作“动态绑定”或“运行期绑定”。(函数调用)绑定方法若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息。。(函数调用)绑定方法Java中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成final。这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的。为什么要把一个方法声明成final呢?正如上一章指出的那样,它能防止其他人覆盖那个方法。但也许更重要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定。这样一来,编译器就可为final方法调用生成效率更高的代码。(函数调用)绑定方法(函数调用)绑定方法上溯造型可用下面这个语句简单地表现出来:Shapes=newCircle();在这里,我们创建了Circle对象,并将结果句柄立即赋给一个Shape。这表面看起来似乎属于错误操作(将一种类型分配给另一个),但实际是完全可行的——因为按照继承关系,Circle属于Shape的一种。因此编译器认可上述语句,不会向我们提示一条出错消息。当我们调用其中一个基础类方法时(已在衍生类里覆盖):s.draw();同样地,大家也许认为会调用Shape的draw(),因为这毕竟是一个Shape句柄。那么编译器怎样才能知道该做其他任何事情呢?但此时实际调用的是Circle.draw(),因为后期绑定已经介入(多形性)。6.2继承层次结构中对象间的关系继承层次结构中的子类对象可以视为超类的对象,这样就可以将子类对象赋给超类变量。然而,超类对象并不是其任何子类的对象,即不能将超类对象赋给子类引用。6.2继承层次结构中对象间的关系(续)例如:Point3point=newPoint3(30,50);Circle4circle=newCircle4(120,89,2.7);Point3pointRef=circle;(允许)Point3pointRef=newCircle4(120,12,0)(允许)pointRef.toString();//callCircle4.toString();pointRef=point;pointRef.toString()//callPoint.toString();Circlecircle=point;//不允许,编译出错Circle4Point3与引用变量指向的对象相关强制类型转换下列语句组是将point对象强制转换成Circle对象,circle.getX()语句是正确的,而circle.getRadius()语句在运行时会产生错误。因为circle引用指向的point对象根本无getRadius方法。Point3point=newPoint3(30,50);Circlecircle=(Circle)point;circle.getX();circle.getRadius();//run-timeerror例6-1中的例子举例说明了继承层次结构中对象间的关系。6.2继承层次结构中对象间的关系(续)例6-2超类对象的引用赋给一个子类类型的变量//HierarchyRelationshipTest2.javapublicclassHierarchyRelationshipTest2{publicstaticvoidmain(String[]args){Point3point=newPoint3(30,50);Circle3circle;circle=point;//超类对象的引用赋给一个子类类型的变量,是不允许的。}}6.3抽象类和抽象方法6.3.1抽象类和具体类的概念6.3.2抽象方法的声明6.3.3抽象类的声明6.3.4抽象类程序设计的举例6.3.1抽象类和具体类的概念抽象类:每个抽象类中至少包含一个抽象方法。抽象类只能作为继承层次结构中的超类,所以这些类称为抽象超类。不能实例化抽象类的对象。抽象类的目的是提供一个合适的超类,以派生其他类。具体类:用于实例化对象的类。这种类实现它们声明的所有方法。抽象超类是一般类,它们仅仅指定子类的共同点,并不创建出真实的对象。例如,如果我们要“绘制形状”,那我们将绘制什么形状呢?具体类为实例化对象提供了合理的细节。6.3.2抽象方法的声明用关键字abstract声明抽象方法:publicabstractvoiddraw();抽象方法并不提供实现。包含抽象方法的类必须声明为抽象类。抽象超类的所有具体子类都必须为超类的抽象方法提供具体实现。6.3.3抽象类的声明使用关键字abstract声明抽象类。形如:publicabstractclassShape{….}抽象类通常包含一个或多个抽象方法(静态方法不能为抽象方法)。抽象超类不能实例化。但可以使用抽象超类来声明引用变量,用以保存抽象类所派生的任何具体类的对象。程序通常使用这种变量来多态地操作子类对象。6.3.4抽象类程序设计的举例•例6-3抽象类的程序设计示例该例子所使用到的类的层次结构如图6-1所示。类的层次以抽象超类Shape为开始,派生出Point类,然后由Point类派生出Circle类,再由Circle类派生出Cylinder类。其中Shape以斜体字出现表示它是抽象类。图6-1Shape类的层次结构6.4接口的声明和实现6.4.1接口的概念6.4.2接口的声明6.4.3接口的实现6.4.4接口的程序设计举例6.4.1接口的概念接口:用于声明一组类的公共操作的接口。接口由常量和一组抽象方法组成。接口中不包括变量和有具体实现的方法。接口只是声明了功能是什么(方法头),而并没有定义如何实现这个功能,功能的实现(即方法体)是在继承这个接口的各个子类中完成的.接口支持多重继承,在Java中,通常把对接口功能的继承称为“实现(implement)”。接口与抽象类到底有什么区别:(1)接口不能实现任何方法,而抽象类可以。(2)类可以实现许多接口,但只有一个父类。(3)接口不是类分级结构的一部分,没有联系的类可以实现相同的接口。6.4.1接口的概念(续)6.4.2接口的声明定义接口的一般格式如下:[public]interface接口名[extends父接口名列表]{//常量声明[public][final][static]类型变量名=常量值;//抽象方法声明[public][abstract]返回类型方法名(参数列表);}接口支持多重继承:接口的定义举例:6.4.2接口的声明(续)publicinterfaceStockWatcher{finalStringsunTicker=SUNW;finalStringoracleTicker=ORCL;finalStringciscoTicker=CSCO;voidvalueChanged(StringtickerSymbol,doublenewValue);}publicinterfaceShape{publicfinalstaticdoublePI=3.1416;publicabstractvoiddraw(Graphicsg);}6.4.3接口的实现为了使用接口,要编写实现接口的类。如果一个类实现一个接口,且实现接口中声明的所有方法时,那么这个类才是具体的类,否则它还是一个抽象的类。具体的类才能用来定义对象,抽象的类是不能实例化的。为了声明一个类来实现一个接口,在类的声明中要包括一条implements语句。一个类可以实现多个接口,因此可以在implements后面列出由类实现的接口系列,这些接口以逗号分隔。classClassNameextendsParentClassimplementsinterface1,interface2{…//接口中方法的实现}6.4.4接口的程序设计举例下面举例说明接口的使用。该例子中各类之间的层次关系如图6-1,仅仅区别在于用接口Shape替代了抽象超类Shape。例6-4接口程序设计示例publicinterfaceShape{//声明了Shape接口publicdoublegetArea();//声明getAre
本文标题:chapter06多态性.
链接地址:https://www.777doc.com/doc-2905263 .html