[学习笔记][Java编程思想]第8章:多态

  • 多态(动态绑定、后期绑定或运行时绑定)是继数据抽象和继承之后的第三种基本特征。
  • 多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来。
  • “封装”通过合并特征和行为来创建新的数据类型。“实现隐藏”则通过将细节“私有化”把接口和实现分离开来。
  • 继承允许将对象视为它自己本身的类型或其基类类型来加以处理。
  • 多态的作用则是消除类型之间的耦合关系,允许一种类型表现出与其他相似类型之间的区别。

1 再论向上转型

  • 将某个对象的引用视为对于基类型的引用的做法称为向上转型。

1.1 忘记对象类型

  • 需要为每一个导出类编写特定类型的方法。

2 转机

2.1 方法调用绑定

  • 将一个方法调用同一个方法主体关联起来被称作绑定。
  • 若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。
  • 后期绑定(动态绑定、运行时绑定),就是在运行时根据对象的类型进行绑定。
  • 编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体。
  • 除了static方法和final方法之外,其他所有的方法都是后期绑定。

2.2 产生正确的行为

  • 在编译时,编译器不需要获得任何特殊信息就能进行正确的调用。
  • Anywhere we override, we use that version, as in Circle; otherwise we use the
    default base-class version.

2.3 可扩展性

  • 只与基类接口通信的程序是可扩展的。
  • 多态将改变的事物与未变的事物分离开来。
  • Java always uses the most-derived method for the object type, this is very powerful
    (and may surprise the unaware). The Template Method design pattern makes heavy use of polymorphism.

2.4 缺陷:“覆盖”私有方法

  • 只有非private方法才可以被覆盖。

2.5 缺陷:域与静态方法

  • 只有普通的方法调用可以是多态的。
  • 如果某个方法是静态的,它的行为就不具有多态性。静态方法是与类,而并非与单个的对象相关联。

3 构造器和多态

  • 构造器并不具有多态性。

3.1 构造器的调用顺序

  • 构造器的特殊任务:检查对象是否被正确地构造。
  • 调用构造器顺序
    • 调用基类构造器。
    • 按声明顺序调用成员的初始化方法。
    • 调用导出类构造器的主体。
  • 当成员对象在类内进行定义的时候,应尽可能对它们进行初始化。

3.2 继承与清理

  • 销毁的顺序应该和初始化顺序相反,对于字段,则意味着与声明的顺序相反。
  • 如果成员对象存在多个对象共享的情况,使用引用计数来跟踪依旧访问着共享对象的对象数量。

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

  • 构造器的工作实际上是创建对象。
  • 在一个构造器的内部调用正在构造的对象的某个动态绑定方法,一个动态绑定的方法调用会向外深入到继承层次结构内部,可以调用导出类里的方法,这个方法所操纵的成员可能还未进行初始化。
  • 初始化过程
    • 将分配给对象的存储空间初始化成二进制的零。
    • 调用基类构造器。
    • 按照声明的顺序调用成员的初始化方法。
    • 调用导出类的构造器主体。
  • 编写构造器准则:用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其他方法。在构造器内唯一能够安全调用的那些方法是基类中的final方法。

4 协变返回类型

  • 协变返回类型,表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型。

5 用继承进行设计

  • 组合比继承更灵活,可以动态选择类型,在运行期间获得动态灵活性(也称状态模式)。
  • 用继承表达行为间的差异,并用字段表达状态上的变化。

5.1 纯继承与扩展

  • 纯继承,只有在基类中已经建立的方法才可以在导出类中被覆盖,“is=a”关系。在使用它们时,完全不需要知道关于子类的任何额外信息。
  • 扩展,“is-like-a”关系,导出类中接口的扩展部分不能被基类访问。

5.2 向下转型与运行时类型识别

  • 向上转型会丢失具体的类型信息。
  • 所有转型都会得到检查,如果不是正确的类型,会返回一个ClassCastException(类转型异常),称作“运行时类型识别”(RTTI),
  • RTTI可以在试图向下转型之前,查看你所要处理的类型。

6 总结

  • 扩展自己的编程视野,使其不仅包括个别类的成员和消息,而且还要包括类与类之间的共同特性以及它们之间的关系。

疑问和总结

1. 继承重写,可以改变方法的权限吗?

  • 导出类重写方法可以扩大基类权限(protected→public),不能缩小基类权限(public→protected)。

你可能感兴趣的:(java)