面向对象:多态与接口
更新时间:2026-08-25。本文是
languages/oop/主题第 ③ 篇。多态是 OOP 的最高境界——让"调用方依赖抽象、运行期替换实现",代码因此可扩展而无需改动。
本文要回答的问题
- 多态在运行期到底发生了什么?什么是动态绑定?
- 接口/虚函数/Go interface 怎么实现多态?
- 为什么多态是"依赖倒置"的基石?
一、多态的本质:一个接口,多种行为
java
interface Shape { double area(); } // 抽象接口
class Circle implements Shape {
private double r;
public double area() { return Math.PI * r * r; }
}
class Square implements Shape {
private double s;
public double area() { return s * s; }
}
// 调用方只依赖 Shape 接口:
double total(List<Shape> shapes) {
return shapes.stream().mapToDouble(Shape::area).sum();
}- 编译期:
total()只认识Shape,不知道具体是 Circle 还是 Square。 - 运行期:
shape.area()根据对象实际类型调用对应实现——这就是动态绑定。
二、动态绑定:虚方法表(vtable)
多态在机器层面靠虚方法表(Java 叫方法表,C++ 叫 vtable)实现:

过程:每个对象带一个指向 vtable 的指针;调用虚方法时先查表拿函数地址,再跳转调用——多一次间接访存 + 一次间接跳转。
| 绑定方式 | 时机 | 依据 | 性能 |
|---|---|---|---|
| 静态绑定 | 编译期 | 声明类型 | 直接调用,零开销 |
| 动态绑定 | 运行期 | 实际类型 | 查表 + 间接跳转 |
三、多语言的多态实现
3.1 Java:接口 + 覆写
java
interface Shape { double area(); } // 接口纯契约
class Circle implements Shape { ... }3.2 C++:虚函数 + 纯虚
cpp
class Shape {
public:
virtual double area() = 0; // 纯虚函数 → 抽象类
};
class Circle : public Shape {
double area() override { return M_PI * r * r; }
};
Shape *s = new Circle(); // 指向子类,动态绑定3.3 Go:隐式接口(duck typing)
go
type Shape interface { Area() float64 } // 接口
type Circle struct{ r float64 }
func (c Circle) Area() float64 { return math.Pi * c.r * c.r }
var s Shape = Circle{r: 2} // 无需 implements,满足方法集即实现Go 接口是隐式实现(结构满足接口的方法签名即算实现)——比 Java 的显式 implements 更解耦。
四、多态的价值:开闭原则 + 依赖倒置
4.1 开闭原则(OCP)
多态让代码"对扩展开放、对修改关闭":新增 Triangle 只需 implements Shape,无需改动 total()。

4.2 依赖倒置原则(DIP)
- 高层模块不依赖低层模块,二者都依赖抽象。
- 抽象不依赖细节,细节依赖抽象。
total()(高层)只依赖 Shape 抽象,不依赖 Circle/Square 细节——替换实现、加新实现都不动高层,这就是多态的解耦威力。
五、多态 vs 继承 vs 接口
| 手段 | 关系 | 绑定 | 解耦度 | 用途 |
|---|---|---|---|---|
| 继承 | is-a | 静态 | 中 | 复用 + 类型替换 |
| 接口 | can-do | 动态 | 高 | 定义能力契约 |
| 多态 | 运行期替换 | 动态 | 最高 | 依赖倒置、策略替换 |
六、与本站主线衔接
- 性能:动态绑定 = 一次 vtable 查表 + 间接跳转,可能打乱分支预测、影响 I-cache——高频热路径可考虑静态分发/模板(C++)或
final方法(Java 可内联)。详见 L3 缓存 与 L4 分支预测。 - 设计模式:多态是策略模式、观察者模式、模板方法的核心机制。
- Java:方法表与 JIT 内联、接口默认方法,见 Java 核心。
- C++:虚函数代价、
final关闭虚化,见 C++ 现代特性。
一句话总结
多态 = 运行期动态绑定,让调用方依赖抽象(接口/虚函数/隐式 interface)而非具体实现;它是开闭原则与依赖倒置的机器级基石,代价是 vtable 查表与间接跳转。