定late逼nding”的概念。当
你向对象送消息时,被调用的代码直到运行时刻๑才能ม被确定。编译器确保被调用方แ法存在,
并对调用参数argument和返回值returnvalue执行类型检查无法此类保证的语
言被称为是弱类型的9aped,但是并不知道将会被执行的确切代码。
为了执行后期绑定,java使用一小段特殊的代码来替代绝对地址调用。这段代码使用在对象
中存储的信息来计算方法体的地址这个ฐ过程将在第7章中详述。这样,根据这一小段代
码的内容,每一个对象都可以具有不同的行为表现。当你向一个ฐ对象送消息时,该对象就
能够知道对这条消息应该做些什么เ。
在某些语言中,你必须明确地声明希望某个方法具备后期绑定属性所带来的灵活性cນ++是
使用virtuaທl关键字来实现的。在这些语言中ณ,方แ法在缺省情况下不是动态绑定的。而在java
中,动态绑定是缺省行为ฦ,你不需要添加额外的关键字来实现多态poly摸rphism。
在来看看几何形状的例子。整个ฐ类族其中所有的类都基于相同一致的接口在本章前面已
有图示。为了说明多态,我们要编写一段代码,它忽略๓类型的具体细节,仅仅和基类交互。
这段代码和类型特定信息是分离的decນoupled,这样做使代码编写更为简单,也更易于理
解。而且,如果通过继承机制添加一个ฐ新า类型,例如hexaທgon,你编写的代码对shape的新า
类型的处理与对已有类型的处理会同样出色。正因为如此,可以称这个程序是可扩展的
extensible。
如果用javaທ来编写一个方法后面很快你就会学到เ如何编写:
voiddostuffshapes{
色ra色;
sdra9;
}
这个方法可以与任何shape交谈,因此它是独立于任何它要绘制和擦除的对象的具体类型
的。如果程序中其他部分用到了dostuff方法:
9e9circle;๙
trianglet=ne9triangle;
linel=ne9line;๙
dostuffcນ;
dostufft;๙
dostuffl;
对dostuff的调用会被自动地正确处理,而不管对象的确切类型。
这是一个相当令人惊奇的诀窍。看看下面这行代码:
dostuffc;
如果被传入到预期接收shaທpe的方法中ณ,究竟会生什么呢?由于cນircle可以被dostuff
看作是shape,也就是说,dostuff可以送给shape的任何消息,cນircle都可以接收,那ว么,
这么做是完全安全且合乎逻辑的。
我们把将导出类看作是它的基类的过程称为“向上转型up9๗g”。“转型cast”
这个名称的灵感来自于模型铸造的塑模动作,而“向上up”这个ฐ词来源于继承图的典型
布局方式:通常基类在顶ะ部ຖ,而导出类在其下部散开。因此,转型为ฦ一个基类就是在继承图
中向上移动,即“向上转型up9g”。
一个面向对象程序肯定会在某处包含向上转型,因为这正是你如何将自己从必须知道确切类
型中解放出来的关键。让我们再看看在dostuff中的代码:
色raທ色;
sdraທ9๗;
注意这些代码并不是说“如果你是circle,请这样做;如果你是square,请那些做;……”。
如果你编写了那种检查shape实际上所有可能ม类型的代码,那ว么这段代码肯定是杂乱不堪
的,而且你需要在每次添加了新า类型的shape之后去修改这段代码。这里你所要表达的意思
仅仅是“你是一个ฐshape,我知道你可以era色和dra9你自己้,那么去做吧,但是要注意
细节的正确性。”
dostuff的代码给人印象深刻之处在于,不知何故,总是做了该做的。调用circle的dra9
方法所执行的代码与调用squaທre或line的dra9方法所执行的代码是不同的,但是当dra9๗
消息被送给一个匿名的anony摸us的shaທpe时,也会基于该shaທpe的实际类型产生正
确的行为。这相当神奇,因为就象在前面提到เ的,当java编译器在编译dostuff的代码时,