Java多态与虚方法表:为什么父类引用无法调用子类新增方法?
报错代码:
1 | package com.torch; |
在 Java 中,虚方法表(vtable) 是实现多态的核心机制。结合虚方法表,我们可以更清晰地理解为什么 cat.sleep()
会编译报错,以及多态是如何工作的。
1. 虚方法表的概念
- 虚方法表是每个类在 JVM 方法区中维护的一张表,记录了该类的所有虚方法(可被重写的方法)的实际入口地址。
- 非虚方法(如
static
、private
、final
方法)不会出现在虚方法表中,它们的调用在编译时直接绑定。
2. 类的虚方法表结构
以下示例中类的虚方法表如下:
Animal
类的虚方法表
1 | Animal 的虚方法表: |
Cat
类的虚方法表
1 | Cat 的虚方法表: |
Dog
类的虚方法表
1 | Dog 的虚方法表: |
3. 多态调用的核心规则
- 编译时检查:基于引用类型(
Animal
)的虚方法表。 - 运行时绑定:基于实际对象类型(
Cat
)的虚方法表。
4. 问题分析:为什么 cat.sleep()
编译报错?
代码片段
1 | Animal cat = new Cat(); |
关键原因
编译时检查:
- 变量
cat
的编译时类型是Animal
。 - 编译器会检查
Animal
类的虚方法表,发现其中没有sleep()
方法。 - 因此直接报错:
Animal 类型没有 sleep() 方法
。
- 变量
运行时绑定:
- 虽然实际对象是
Cat
,且Cat
的虚方法表中有sleep()
方法。 - 但编译时的检查已经失败,代码无法进入运行阶段。
- 虽然实际对象是
5. 虚方法表的运行时行为
如果通过强制类型转换调用 sleep()
:1
((Cat) cat).sleep(); // 编译通过,运行时调用 Cat.sleep()
运行时步骤:
- 强制转换:告诉编译器
cat
实际是Cat
类型。 - 编译检查:检查
Cat
的虚方法表,发现sleep()
方法存在。 - 运行时绑定:通过
Cat
的虚方法表找到sleep()
的入口地址,执行具体实现。
6. 多态的核心总结
阶段 | 规则 |
---|---|
编译时 | 基于引用类型的虚方法表检查方法是否存在。 |
运行时 | 基于实际对象类型的虚方法表动态绑定方法实现。 |
- 父类引用无法调用子类新增方法:因为父类的虚方法表中没有该方法。
- 重写方法可以动态绑定:因为子类的虚方法表会覆盖父类方法的入口地址。
7. 最终结论
cat.sleep()
编译报错的根本原因是:编译时检查基于 Animal
的虚方法表,而 Animal
的虚方法表中没有 sleep()
方法。虚方法表机制确保了多态的安全性和灵活性,但编译时的类型检查仍然是严格基于引用类型的。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Torch's blog!