java方法重写通过invokevirtual指令与虚方法表(vtable)实现运行时多态:jvm从对象头获取真实class,按固定索引查子类vtable中已预设的方法地址,无需遍历,高效确定。

Java 中方法重写实现运行时多态,核心就靠 invokevirtual 指令配合虚方法表(vtable)完成寻址。它不依赖编译时类型,而是根据对象**实际类型**查表跳转,整个过程高效且确定。
寻址起点:从对象头拿到真实类信息
执行 invokevirtual 时,JVM 先从操作数栈顶取出对象引用,再通过该引用的对象头(Object Header)读取其 klass 指针——这个指针直接指向堆中该对象的真实 Class 对象(比如是 Dog.class,不是声明类型的 Animal.class)。
查表依据:每个类加载时已构建好 vtable
vtable 是 JVM 在类加载阶段为每个类生成的一张函数指针数组,结构固定、索引预设:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 所有可被重写的实例方法(public/protected、非 static、非 private、非 final)按签名顺序填入表中
- 子类 vtable 继承父类结构,仅将被重写的方法槽位替换为自己的入口地址
- 同一个方法签名(如
makeSound()V)在父类和子类 vtable 中位于**相同索引位置**,这是单继承保障的
定位目标:符号引用 → 索引 → 地址
字节码中的 invokevirtual Animal.makeSound:()V 只是一个符号引用,不含具体地址。JVM 执行时做三步转换:
- 从常量池解析该符号,得到方法名与描述符(
makeSound()V) - 根据该签名,在当前类(即真实类型,如
Dog)的 vtable 中计算对应槽位索引(类加载时已静态确定) - 直接读取 vtable[索引] 处存储的字节码入口地址,跳转执行
为什么不用遍历或搜索?
因为 vtable 的布局是编译期和类加载期联合约定好的:
- 新增方法只追加到表尾,不影响已有方法索引
- 重写不改变位置,只更新槽内地址
- JIT 编译后甚至能进一步优化为直接偏移访问(如
mov rax, [rax + 0x28]),查表开销极小
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










