10.1.4 多态与动态绑定的基本概念
多态和动态绑定是继承、重写之后自然出现的概念。不同子类继承同一个父类方法后,可以给出不同实现;当外部发送同一消息时,运行时根据实际对象决定执行哪个实现。
多态是什么
多态的直观定义是:不同对象接收相同消息,产生不同响应。
例如父类 Animal 定义 call(),子类 Cat 和 Dog 都继承它,但分别重写为不同实现。外部同样调用 call(),实际响应取决于对象到底是 Cat 还是 Dog。
mermaid
classDiagram
class Animal {
+call()
}
class Cat {
+call()
}
class Dog {
+call()
}
Animal <|-- Cat
Animal <|-- Dog同一接口、不同实现,是多态的核心价值。
动态绑定
绑定是把“方法调用”与“具体方法实现”关联起来。动态绑定表示这种关联在运行时确定。
| 绑定方式 | 何时确定调用目标 | 特点 |
|---|---|---|
| 静态绑定 | 编译期 | 调用目标提前确定,通常效率高 |
| 动态绑定 | 运行期 | 根据实际对象类型选择方法,支持多态 |
当父类引用指向子类对象时,代码表面上调用的是父类接口,但运行时执行的是实际子类实现。这个“运行时决定”的过程就是动态绑定。
多态为什么重要
多态让代码依赖抽象,而不是依赖具体类。这样新增子类时,调用方可以不改或少改。
java
void makeSound(Animal animal) {
animal.call();
}makeSound() 不关心传入的是 Cat 还是 Dog,只要它是 Animal 的子类并实现 call()。这会提升扩展性。
多态、重写、动态绑定的关系
| 概念 | 作用 |
|---|---|
| 继承 | 建立父类与子类关系 |
| 重写 | 子类提供不同方法实现 |
| 多态 | 同一消息在不同对象上表现不同 |
| 动态绑定 | 运行时决定调用哪个对象的实现 |
多态通常依赖继承和重写,动态绑定则是多态在运行时生效的重要机制。
重载与多态的边界
重载也可能被称为一种多态形式,但软考概念题更常要求你区分:
| 概念 | 关键区别 |
|---|---|
| 重载 | 同一类中同名方法参数不同,常在编译期决定 |
| 重写 | 子类重新实现父类同名同参数方法 |
| 动态绑定 | 运行时根据实际对象类型选择重写后的方法 |
看到“同名不同参数”,先想到重载;看到“子类覆盖父类方法”,先想到重写;看到“运行时决定”,先想到动态绑定。
多态的分类
字幕里提到软考曾考过“同一操作名在不同上下文中含义不同”对应哪类多态。这里要知道几类说法:
| 类型 | 含义 | 关键词 |
|---|---|---|
| 过载多态 | 同名操作在不同上下文中代表不同含义 | 同名、上下文不同、重载 |
| 参数多态 | 操作可作用于多种参数类型 | 泛型、参数类型变化 |
| 包含多态 | 父类型变量可包含子类型对象 | 子类型化、继承、多态 |
| 强制多态 | 通过类型转换让操作适配不同类型 | 强制类型转换 |
目前考试更常见的是过载多态。看到“操作方法具有相同名称,在不同上下文中含义不同”,优先想到过载多态。
例题
运行时根据实际对象类型决定调用哪个方法,称为:
多态更准确的描述是:
本节小结
多态是“同一消息,不同响应”;动态绑定是在运行时根据实际对象类型选择方法实现。继承建立类型层次,重写提供不同实现,动态绑定让多态真正发生。重载看参数,重写看父子类覆盖,动态绑定看运行时;过载多态强调同名操作在不同上下文中含义不同。