java 多态(二)

一、构造器内部的多态方法的行为

构造器调用的层次结构带来了一个有趣的两难问题。如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,那会发生什么情况呢?

在一般的方法内部,动态绑定的调用是在运行时才决定的,因为对象无法知道它是属于方法所在的那个类,还是那个类的导出类。

如果要调用构造器内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。然而,这个调用的效果可能相当难于预料,因为被覆盖的方法在对象被完全构造之前就会被调用。这可能会造成一些难于发现的隐藏错误。

从概念上讲,构造器的工作实际上是创建对象。在任何构造器内部,整个对象可能只是部分形成-----我们只知道基类对象已经进行初始化。如果构造器只是在构建对象过程中的一个步骤,并且该对象所属的类是从这个构造器所属的类导出的,那么导出部分在当前构造器正在被调用的时刻仍旧是没有被初始化的。然而,一个动态绑定的方法调用却会向外深入到继承层次结构内部,它可以调用导出类里的方法。如果我们是在构造器内部这么做,那么就可能会调用这个方法,而这个方法所操纵的成员可能还未进行初始化----这肯定会招致灾难。

通过下面这个例子,我们会看到问题所在:

public class Glyph {
void draw(){
System.out.println("Glyph.draw()");
}

Glyph(){
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}


public class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
System.out.println("RoundGlyph.RoundGlyph(), radius = "+radius);
}

void draw(){
System.out.println("RoundGlyph.draw(), radius = "+radius);
}
}


public class PolyConstructors {
public static void main(String[] args){
new RoundGlyph(5);
}
}

/output:

Glyph() before draw()

RoundGlyph.draw(), radius = 0

Glyph() after draw()

RoundGlyph.RoundGlyph(), radius =5


Glyph.draw()方法设计将要被覆盖,这种覆盖在RoundGlyph中发生的。但是Glyph构造器会调用这个方法,结果导致了对RoundGlyph.draw()的调用,这看起来似乎是我们的目的。但是看到输出结果,我们会发现当Glyph的构造器调用draw()方法时,radius不是默认初始值1,而是0。

初始化的顺序是解决这一谜题的关键所在初始化的实际过程是:

1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。

2)如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用)由于步骤1的缘故,我们此时会发现radius的值为0.

3)按照声明的顺序调用成员的初始化方法。

4)调用导出类的构造器主体。

这样做有一个优点,那就是所有东西都至少初始化为零,而不是仅仅留作垃圾。其中包括通过“组合”而嵌入一个类内部的对象引用,其值是null。所以如果忘记为该引用进行初始化,就会在运行时出现异常,查看输出结果时,会发现其他所有东西的值都会是零,这通常也正是发现问题的证据。


二、用继承进行设计

学习了多态之后,看起来似乎所有东西都可以被继承,因为多态是一种如果巧妙的工具。事实上,当我们使用现成的类来建立新类时,如果首先考虑使用及恒技术,反倒会加重我们的设计负担,使事情变得不必要地复杂起来。

更好的方式是首先选择“组合”,尤其是不能十分确定应该使用哪一种方式时。组合不会强制我们的程序设计进入继承的层次结构中。而且,组合更加灵活,因为它可以动态选择类型。相反,继承在编译时就需要知道确切类型。


三、总结

多态意味着“不同的形式”。在面向对象的程序设计中,我们持有从基类继承而来的相同接口,以及使用该接口的不同形式:不同版本的动态绑定方法。

如果不运用数据抽象和继承,就不可能理解或甚至不能创建多态的例子。多态是一种不能单独来看待的特性。相反它只能作为类关系“全景”中的一部分,与其他特性协同工作。

为了在自己的程序中有效地运用多态乃至面向对象的技术,必须扩展自己的编程视野,使其不仅包括个别类的成员和信息,而且还要包括类与类之间的共同特性以及它们之间的关系。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值