一、概念
动态链接(或指向运行时常量池的方法引用)
- 每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用。
- 包含这个引用的目的就是为了支持当前方法的代码能够实现动态链接(Dynamic Linking),比如:invokedynamic指令
- 在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用(Symbolic Reference)保存在class文件的常量池里,程序运行时将其加载进方法区的运行时常量池中。
- 比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。
为什么要用常量池呢?
- 因为在不同的方法,都可能调用常量或者方法,所以只需要存储一份即可,然后记录其引用即可,节省了空间。
- 常量池的作用:就是为了提供一些符号和常量,便于指令的识别。
个人总结(谨慎入脑)
- java文件编译后即生成指令集和常量池。
- 动态链接就是将指令中的符号引用转化为真实的方法地址。(依据常量池)
- 为何不直接在指令中确认方法的真实地址。个人理解应该是方法可能被多处调用,将方法地址统一放在一个地方并编号,只需要将号给到指令即可。
后续纠正补充
定义两个类,One和Two,分别包含方法Method1和Mwthod2,如下为Two类的详细信息
- 编译完成后,会生成指令集和常量池(Constant pool)
- 动态链接就是在运行时,将指令中的符号引用转化为真实的地址。(依据常量池)
- 根据符号引用去常量池中寻找并转化为注释中的内容。
- 常量池存储每个符号引用对应的真实地址。虚指令包含符号引用,指向运行时常量池的方法引用。
- 白话就是把需要用到的方法真实地址,存放在常量池中,并标号,不同的方法调用指令只需要记住这个号即可。用到的时候拿号去找。
Classfile /E:/Software/IDEAProject/TestProject/JavaEnhance/out/production/JavaEnhance/com/fangk/enhance/ClassTwo.class
Last modified 2020-12-5; size 481 bytes
MD5 checksum 2f4be3b4aea26b3e765abe2a3609ccb3
Compiled from "ClassTwo.java"
public class com.fangk.enhance.ClassTwo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#19 // java/lang/Object."<init>":()V
#2 = Class #20 // com/fangk/enhance/ClassOne
#3 = Methodref #2.#19 // com/fangk/enhance/ClassOne."<init>":()V
#4 = Methodref #2.#21 // com/fangk/enhance/ClassOne.method1:()V
#5 = Class #22 // com/fangk/enhance/ClassTwo
#6 = Class #23 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/fangk/enhance/ClassTwo;
#14 = Utf8 method2
#15 = Utf8 classOne
#16 = Utf8 Lcom/fangk/enhance/ClassOne;
#17 = Utf8 SourceFile
#18 = Utf8 ClassTwo.java
#19 = NameAndType #7:#8 // "<init>":()V
#20 = Utf8 com/fangk/enhance/ClassOne
#21 = NameAndType #24:#8 // method1:()V
#22 = Utf8 com/fangk/enhance/ClassTwo
#23 = Utf8 java/lang/Object
#24 = Utf8 method1
{
public com.fangk.enhance.ClassTwo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/fangk/enhance/ClassTwo;
public void method2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: new #2 // class com/fangk/enhance/ClassOne
3: dup
4: invokespecial #3 // Method com/fangk/enhance/ClassOne."<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #4 // Method com/fangk/enhance/ClassOne.method1:()V
12: return
LineNumberTable:
line 5: 0
line 6: 8
line 8: 12
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 this Lcom/fangk/enhance/ClassTwo;
8 5 1 classOne Lcom/fangk/enhance/ClassOne;
}
SourceFile: "ClassTwo.java"