静态链接与动态链接的核心差异在于符号引用解析时机:前者在编译或类加载链接阶段完成地址绑定,后者推迟到运行时根据实际类型动态查找;静态链接适用于static/private/final等不可重写方法,性能高但不支持多态,动态链接支撑Java多态,通过虚方法表实现运行时绑定。

静态链接和动态链接的核心差异,在于方法调用的符号引用何时被解析为真实内存地址——前者在类加载的链接阶段完成,后者推迟到运行期才确定。
静态链接:编译期可知,加载期即绑定
当一个方法在编译时就能唯一确定(比如 static、private、final 方法,或构造器),JVM 在类加载的“链接”阶段,就会把常量池里的符号引用(如 #23)直接替换成指向具体方法区中元数据的直接引用。这个过程不可更改,也不依赖对象实际类型。
常见表现:
- 字节码中使用 invokestatic 或 invokespecial 指令
- 调用目标与变量声明类型强绑定,不支持多态
- 性能高,无运行时查找开销
动态链接:运行期才查,靠实际类型决定
对于可能被重写的方法(如普通实例方法),编译期只知道调用的是某个父类声明的方法,但无法预知子类是否覆盖。因此,JVM 不在加载时做最终绑定,而是把符号引用保留在常量池中,等到真正执行 invokevirtual 或 invokeinterface 指令时,再根据栈帧中对象的实际运行时类型,从其类元数据的方法表里查找匹配方法。
这正是 Java 多态的底层支撑机制:
- 每次调用都要查虚方法表(vtable)或接口方法表(itable)
- 支持子类替换父类行为,但带来少量运行时开销
- 即使变量声明为父类类型,只要运行时是子类实例,就调用子类版本
不是所有“继承”都触发动态链接
能否动态链接,关键看方法是否“可被重写”。即便在继承体系中:
- static 方法始终静态链接——它属于类,不参与多态
- private 方法虽隐式 final,也只在本类内可见,不会进入子类方法表
- final 实例方法因禁止重写,JVM 可安全静态链接(部分 JIT 甚至会内联)
- 普通 public/protected 非 final 实例方法,默认走动态链接
invokedynamic:为动态语言设计的特殊通道
Java 7 引入的 invokedynamic 指令,不依赖类继承关系,而是通过“引导方法(Bootstrap Method)”在首次调用时动态生成调用点。Lambda 表达式、方法句柄、Groovy/Scala 的动态调用都依赖它。
它和传统动态链接不同:
- 绑定逻辑完全由用户代码控制,而非 JVM 内置规则
- 首次调用较慢(需初始化调用点),后续可优化为直接跳转
- 实现了真正的运行时行为绑定,超越了“基于类型的重写”范畴










