JAVA 6多形性

上传人:206****923 文档编号:52325992 上传时间:2018-08-20 格式:PPT 页数:65 大小:401.50KB
返回 下载 相关 举报
JAVA 6多形性_第1页
第1页 / 共65页
JAVA 6多形性_第2页
第2页 / 共65页
JAVA 6多形性_第3页
第3页 / 共65页
JAVA 6多形性_第4页
第4页 / 共65页
JAVA 6多形性_第5页
第5页 / 共65页
点击查看更多>>
资源描述

《JAVA 6多形性》由会员分享,可在线阅读,更多相关《JAVA 6多形性(65页珍藏版)》请在金锄头文库上搜索。

1、6 多形性Polymorphism1?u什么是多形性Polymorphism?u什么是覆盖与过载?u如何实现内部类? 2u上溯造型u深入理解u覆盖与过载u抽象类和方法u接口u内部类u构建器和多形性u通过继承进行设计3u在java语言中,多形性体现在两个方面:由方法 重载实现的静态多形性(编译时多形)和方法重 写实现的动态多形性(运行时多形)。 t1)编译时多形 在编译阶段,具体调用哪个被重载的方法,编译器会根 据参数的不同来静态确定调用相应的方法。t2)运行时多形 由于子类继承了父类所有的属性(私有的除外),所以 子类对象可以作为父类对象使用。程序中凡是使用父类 对象的地方,都可以用子类对象来

2、代替。一个对象可以 通过引用子类的实例来调用子类的方法。41.上溯造型u可将一个对象作为它自己的类型使用,或者作为它的基 础类型的一个对象使用。取得一个对象句柄,并将其作 为基础类型句柄使用的行为就叫作“上溯造型”因 为继承树的画法是基础类位于最上方。uMusic.javau这里,方法Music.tune()接收一个Instrument句柄,同 时也接收从Instrument衍生出来的所有东西。当一个 Wind句柄传递给tune()的时候,就会出现这种情况。 Instrument里的接口必须存在于Wind中,因为Wind是从 Instrument里继承得到的。从Wind向Instrument的

3、上溯 造型可能“缩小”那个接口,但不可能把它变得比 Instrument的接口还要小。?52.为什么要上溯造型u如果让tune()简单地取得一个Wind句柄,将其作 为自己的自变量使用,似乎会更加简单、直观得 多。但要注意:假如那样做,就需为系统内 Instrument的每种类型写一个全新的tune()。假 设按照前面的推论,加入Stringed(弦乐)和 Brass(铜管)这两种Instrument(乐器)uMusic2.java62.为什么要上溯造型u这样做当然行得通,但却存在一个极大的弊端:必须为每 种新增的Instrument类编写与类紧密相关的方法。这意味 着第一次就要求多得多的编程

4、量。以后,假如想添加一个 象tune()那样的新方法或者为Instrument添加一个新类型 ,仍然需要进行大量编码工作。此外,即使忘记对自己的 某个方法进行过载设置,编译器也不会提示任何错误。这 样一来,类型的整个操作过程就显得极难管理,有失控的 危险。u假如只写一个方法,将基础类作为自变量或参数使用, 而不是使用那些特定的衍生类,岂不是会简单得多?也 就是说,如果能不顾衍生类,只让自己的代码与基础类 打交道,那么省下的工作量将是难以估计的。73.方法调用的绑定u观察一下tune()方法: public static void tune(Instrument i) / . i.play(No

5、te.middleC); u它接收Instrument句柄。所以在这种情况下,编 译器怎样才能知道Instrument句柄指向的是一个 Wind,而不是一个Brass或Stringed呢?编译器无 从得知。为了理解这个问题,这里探讨一下“绑 定”这个主题。83.方法调用的绑定u将一个方法调用同一个方法主体连接到一起就称 为“绑定”(Binding)。若在程序运行以前执行 绑定(由编译器和链接程序,如果有的话),就 叫作“早期绑定”。u上述程序最令人迷惑不解的地方全与早期绑定有 关,因为在只有一个Instrument句柄的前提下, 编译器不知道具体该调用哪个方法。u解决的方法就是“后期绑定”,它

6、意味着绑定在 运行期间进行,以对象的类型为基础。后期绑定 也叫作“动态绑定”或“运行期绑定”。93.方法调用的绑定u要实现后期绑定,同时必须提供一些机制,可在运行期 间判断对象的类型,并分别调用适当的方法。也就是说 ,编译器此时依然不知道对象的类型,但方法调用机制 能自己去调查,找到正确的方法主体。u不同的语言对后期绑定的实现方法是有所区别的。但我 们可以这样认为:它们都要在对象中安插某些特殊类型 的信息。uJava中绑定的所有方法都采用后期绑定技术,除非一个 方法已被声明成final。这意味着我们通常不必决定是否 应进行后期绑定它是自动发生的。它可有效地“关 闭”动态绑定,编译器就可为fin

7、al方法调用生成效率更 高的代码。103.方法调用的绑定u经典的“形状”的例子。形状例子有一个基础类,名为 Shape;另外还有大量衍生类型:Circle(圆形), Square(方形),Triangle(三角形)等等。这里,很 容易理解“圆属于形状的一种类型”等概念。下面继承 图展示了它们的关系:113.方法调用的绑定u上溯造型可用下面这个语句简单地表现出来:Shape s = new Circle();u在这里,创建了Circle对象,并将结果句柄立即赋给一 个Shape。这表面看起来似乎属于错误操作(将一种类型 分配给另一个),但实际是完全可行的因为按照继 承关系,Circle属于Sha

8、pe的一种。因此编译器认可上述 语句,不会提示一条出错消息。123.方法调用的绑定u当调用其中一个基础类方法时(已在衍生类里覆盖):s.draw();u同样地,大家也许认为会调用Shape的draw(),因为这毕 竟是一个Shape句柄。那么编译器怎样才能知道该做其他 任何事情呢?但此时实际调用的是Circle.draw(),因为 后期绑定已经介入(多形性)。u下面这个例子从一个稍微不同的角度说明了问题:Shapes.java134.扩展性u现在,仍然返回乐器(Instrument)示例。由于存在多 形性,所以可根据自己的需要向系统里加入任意多的新 类型,同时毋需更改tune()方法。在一个设

9、计良好的OOP 程序中,大多数或者所有方法都会遵从tune()的模型, 而且只与基础类接口通信。我们说这样的程序具有“扩 展性”,因为可以从通用的基础类继承新的数据类型, 从而新添一些功能。如果是为了适应新类的要求,那么 对基础类接口进行操纵的方法根本不需要改变。144.扩展性u对于乐器例子,假 设在基础类里加入 更多的方法,以及 一系列新类,那么 会出现什么情况呢 ?下面是示意图:uMusic3.javau多形性是一种至关 重要的技术,它允 许程序员“将发生 改变的东西同没有 发生改变的东西区 分开”。155.抽象类和方法u在所有乐器(Instrument)例子中,基础类Instrument

10、 内的方法都是“伪”方法。若去调用这些方法,就会出 现错误。那是由于Instrument的意图是为从它衍生出去 的所有类都创建一个通用接口。u之所以要建立这个通用接口,原因就是它能为不同的子 类型作出不同的表示。它建立了一种基本形式,能定义 在所有衍生类里“通用”的一些东西。为阐述这个观念 ,另一个方法是把Instrument称为“抽象基础类”(简 称“抽象类”)。165.抽象类和方法u如果有一个象Instrument那样的抽象类,那个类的对象 几乎肯定没有什么意义。换言之,Instrument的作用仅 仅是表达接口,而不是表达一些具体的实施细节。所以 创建一个Instrument对象是没有意

11、义的,而且通常都应 禁止用户那样做。为达到这个目的,可令Instrument内 的所有方法都显示出错消息。但这样做会延迟信息到运 行期,并要求在用户那一面进行彻底、可靠的测试。无 论如何,最好的方法都是在编译期间捕捉到问题。u针对这个问题,Java专门提供了一种机制,名为“抽象 方法”。它属于一种不完整的方法,只含有一个声明, 没有方法主体。下面是抽象方法声明时采用的语法: abstract void X();175.抽象类和方法u包含了抽象方法的一个类叫作“抽象类”。如果一个类里包含了一 个或多个抽象方法,类就必须指定成abstract(抽象)。否则,编 译器会报告一条出错消息。u若一个抽象

12、类是不完整的,那么一旦有人试图生成那个类的一个对 象,编译器又会采取什么行动呢?由于不能安全地为一个抽象类创 建属于它的对象,所以会从编译器那里获得一条出错提示。通过这 种方法,编译器可保证抽象类的“纯洁性”,不必担心会误用它。u如果从一个抽象类继承,而且想生成新类型的一个对象,就必须为 基础类中的所有抽象方法提供方法定义。如果不这样做(完全可以 选择不做),则衍生类也会是抽象的,而且编译器会强迫用 abstract关键字标志那个类的“抽象”本质。u即使不包括任何abstract方法,亦可将一个类声明成“抽象类”。 如果一个类没必要拥有任何抽象方法,而且想禁止那个类的所有实 例,这种能力就会显

13、得非常有用。185.抽象类和方法uInstrument类可很轻 松地转换成一个抽象 类。只有其中一部分 方法会变成抽象方法 ,因为使一个类抽象 以后,并不会强迫将 它的所有方法都同时 变成抽象。下面是它 看起来的样子:uMusic4.java196.接口u“interface”(接口)关键字使抽象的概念更深入了一 层。可将其想象为一个“纯”抽象类。它允许创建者规 定一个类的基本形式:方法名、自变量列表以及返回类 型,但不规定方法主体。接口也包含了基本数据类型的 数据成员,但它们都默认为static和final。接口只提供 一种形式,并不提供实施的细节。u接口这样描述自己:“对于实现我的所有类,

14、看起来都 应该象我现在这个样子”。因此,采用了一个特定接口 的所有代码都知道对于那个接口可能会调用什么方法。 这便是接口的全部含义。所以常把接口用于建立类和类 之间的一个“协议”。有些面向对象的程序设计语言采 用了一个名为“protocol”(协议)的关键字,它做的 便是与接口相同的事情。206.接口u为创建一个接口,使用interface关键字,而不要用 class。与类相似,可在interface关键字的前面增加一 个public关键字(但只有接口定义于同名的一个文件内 );或者将其省略,营造一种“友好的”状态。u为了生成与一个特定的接口(或一组接口)相符的类, 要使用implements

15、(实现)关键字。要表达的意思是“ 接口看起来就象那个样子,这儿是它具体的工作细节” 。除这些之外,其他的工作都与继承极为相似。216.接口u下面是乐器例子的 示意图:uMusic5.java226.接口:Java的“多重继承”u接口只是比抽象类“更纯”的一种形式。它的用途并不 止那些。由于接口根本没有具体的实施细节也就是 说,没有与存储空间与“接口”关联在一起所以没 有任何办法可以防止多个接口合并到一起。这一点是至 关重要的,因为经常都需要表达这样一个意思:“x从属 于a,也从属于b,也从属于c”。u在C+中,将多个类合并到一起的行动称作“多重继承” ,而且操作较为不便,因为每个类都可能有一套

16、自己的 实施细节。236.接口:Java的“多重继承”u在Java中,可采取同样的行动,但只有其中一个类拥有 具体的实施细节。所以在合并多个接口的时候,C+的问 题不会在Java中重演。如下所示:246.接口:Java的“多重继承”u在一个衍生类中,并不一定要拥有一个抽象或具体(没 有抽象方法)的基础类。如果确实想从一个非接口继承 ,那么只能从一个继承。剩余的所有基本元素都必须是 “接口”。将所有接口名置于implements关键字的后面 ,并用逗号分隔它们。可根据需要使用多个接口,而且 每个接口都会成为一个独立的类型,可对其进行上溯造 型。下面这个例子展示了一个“具体”类同几个接口合 并的情况,它最终生成了一个新类:Adventure.java256.接口:Java的“多重继承”u上述例子揭示了接口最关键的作用,也是使用接 口最重要的一个原因:能上溯造型至多个基础类 。使用接口的第二个原因与使用抽象基础类的原 因是一样的:防止客户程序员制作这个类的一个 对象,以及规定它仅仅是一个接口。这样便带来 了一个问题:到底应该使用一个接口还是一个抽 象类呢?若

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 商业/管理/HR > 其它文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号