动态链接负责在类加载解析阶段或运行时将符号引用转为直接引用;符号引用是编译期与内存无关的常量池描述(如类名、方法签名),直接引用是运行时指向内存地址或偏移量的具体指针。

动态链接在 JVM 中负责将类文件里的符号引用(Symbolic Reference)在运行时解析为直接引用(Direct Reference),这个过程发生在类加载的“解析”阶段,核心目标是让方法调用、字段访问等操作能定位到内存中真实的数据结构(如方法区中的方法入口地址、对象实例中的字段偏移量等)。
符号引用和直接引用的区别
符号引用以一组字面量(字符串形式)描述目标,比如:
-
类名:
"java/lang/Object" -
方法名与描述符:
"toString()Ljava/lang/String;" -
字段名与描述符:
"value:[C"
这些不依赖于内存布局,可独立存在于 class 文件中。而直接引用是 JVM 实现层面的指针或偏移量,例如:
- 指向方法区中类元数据的指针
- 指向常量池中已解析项的索引
- 对象内某个实例字段的内存偏移量
- 方法表(vtable / itable)中的槽位索引
解析时机:静态解析 vs. 动态解析
JVM 解析并非全部在类加载时完成,而是分两类:
-
静态解析:在类加载的解析阶段就完成,适用于编译期可知且运行期不变的目标,如
static、private方法,以及final的实例方法(不被重写)。它们的调用指令(如invokestatic、invokespecial)在解析后直接绑定到具体目标。 -
动态解析:对虚方法(
invokevirtual)和接口方法(invokeinterface),JVM 延迟到第一次执行该指令时才做“真正”的目标定位——即根据实际对象类型查 vtable/itable,获得具体方法入口。这属于动态链接的延续,但严格说已超出“解析阶段”,进入“运行期方法分派”范畴。
解析过程的关键步骤
当 JVM 遇到一个未解析的符号引用(如常量池中一个 CONSTANT_Methodref_info),会按以下逻辑尝试转换:
- 检查符号引用所指的类是否已加载、验证、准备;若未完成,则先触发类加载流程
- 根据类的运行时常量池和方法区中的类元数据,查找匹配的类、字段或方法定义
- 校验访问权限(如私有方法能否被调用、包访问是否越界)
- 对于方法,确认签名是否匹配,并检查是否满足重写规则(如返回类型协变)
- 成功后,在当前类的运行时常量池中将该符号引用替换为一个直接引用(例如:指向方法区中该方法
Method结构体的指针,或其在 vtable 中的索引)
为什么需要动态链接?
Java 支持多态和运行时类加载(如反射、OSGi、热更新),无法在编译时确定所有调用目标。动态链接把绑定推迟到运行时,既保证了 class 文件的平台无关性,又支撑了灵活的面向对象特性。没有它,obj.toString() 就无法在子类重写后自动调用子类版本。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











