多态概述
在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。
- 多态不但能够改善代码的组织结构和可读性,还能够创建可扩展的程序。
- 在多态允许我们无需管导出类(子类)的存在,编写的代码只是与基类(父类)打交道
多态别称:又叫动态绑定、后期绑定或运行时绑定
绑定:将一个方法调用与一个方法主体关联起来称作绑定
前期绑定:若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。它是面向过程语言中不需要选择就默认的绑定方式。例如,C只有一种方法调用,那就是前期绑定。
- 后期绑定:就是在运行时根据对象的类型进行绑定。后期绑定也叫做动态绑定或运行时绑定。如果一种语言想实现后期绑定,就必须具有某种机制,以便在运行时能判断对象的类型,从而调用恰当的方法。也就是说,编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,并加以调用。后期绑定机制随编程语言的不同而有所不同,但是只要想一下就会得知,不管怎样都必须在对象中安置某种“类型信息”。
再论final
- 可以防止其他人覆盖该方法
- 还可以有效的”关闭”动态绑定
- private(隐形final)不可被覆盖
论static
- 如果某个方法是静态的,它的行为就不具有多态性
- 静态方法是与类,而非与单个的对象相关联的。
- static不可以被重写,但可以被重载
构造器
- 构造器(隐式static),同样不具有多态性
- 构造器特殊任务:检查对象是否被正确的构造
对象调用构造器遵从顺序:
- 调用基类构造器,这个步骤或不断的反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,直到最底层的导出来
- 按照声明顺序调用成员的初始化方法
- 调用导出类构造器的主体
构造器内部的多态方法的行为
如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,那么会发生什么情况呢?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37/**
* 构造器内部的多态方法的行为
*/
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}
class Glyph{
void draw(){
System.out.println("Glyph.draw()");
}
public Glyph() {
System.out.println("Glyph() before draw()");
draw();
System.out.println("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
public RoundGlyph(int radius) {
this.radius = radius;
System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);
}
void draw(){
System.out.println("RoundGlyph.draw(),radius="+radius);
}
}/*Output:
Glyph() before draw()
RoundGlyph.draw(),radius=0
Glyph() after draw()
RoundGlyph.RoundGlyph(),radius=5
*///:~
由上可以看出,在打印radius时,不是我们默认初始化的1,而是0。违背了我们的初衷。我们要用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法。
初始化的实际过程是:
- 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零
- 如前所述的那样调用及剋构造器。
- 按照声明的顺序调用成员的初始化方法
- 调用导出类的构造主体