动态连接

294 阅读4分钟

动态连接

  1. 每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用。包含这个引用的目的就是为了支撑当前方法的代码能够实现动态连接,比如invokedynamic指令;
  2. 在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用,保存在class文件的常量池里。比如一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态连接的作用就是为了将这些符号引用转换为调用方法的直接引用。

未命名文件 (2).jpg

常量池的作用

就是为了提供一些符号和常量,便于指令的识别

方法返回地址

存放调用该方法的PC寄存器的值 在方法退出后都返回到该方法被调用的位置,方法正常退出时,调用的PC寄存器的值为返回地址,即调用该方法指令的下一条指令的地址,而通过异常退出的,返回地址是通过异常表来确定。

方法的调用

在JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制相关。

静态连接

当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译器可知,且运行期保持不变时,这种情况下将调用方法的符号引用转换为直接应用的过程称之为静态连接。

动态连接

如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称为动态连接。

方法的绑定机制

方法的绑定机制为早期绑定和晚期绑定,绑定时一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。

  1. 早期绑定:指被调用的目标方法如果在编译期可知,且运行期保持不变时,即可将这个方法与所属的类型进行绑定。将符号引用转换为直接引用
  2. 晚期绑定:被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法

非虚方法

静态方法,私有方法,final方法,实例构造器,父类方法。 普通调用指令

  1. invokestatic:调用静态方法,解析阶段确定唯一方法版本
  2. invokespecial:调用方法、私有及父类方法,解析阶段确定唯一方法版本
  3. invokevirtual:调用所有虚方法
  4. invokeinterface:调用接口方法 动态调用指令
  5. invokedynamic:动态解析出需要调用的方法,然后执行

前四条指令固化在虚拟机内部,方法的调用执行不可人为干预,而invokedynamic指令则支持由用户确定方法版本,其中invokestatic指令和invokespecial指令调用的方法称为非虚方法,其余的(final修饰的除外)称为虚方法

Java语言中方法重写的本质

  1. 找到操作数栈顶的第一个元素所执行的对象的实际类型,记作 C.
  2. 如果在过程结束,如果不同类型C中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回方法的直接引用,查找过程结束,如果不通过,则返回Java.lang.IllegalAccessError异常。
  3. 否则按照继承关系从下往上依此对C的各个父类进行第2步的搜索和验证过程
  4. 如果始终没有找到合适的方法,则抛出java.lang.AbstrackMehtodError异常;

IllegalAccessError介绍 程序试图访问或修改一个属性或调用一个方法,这个属性或方法,你没有权限访问,一般的,这个会引起编译器异常,这个错误如果发生在运行时,就说明一个类发生了不兼容的改变。

虚方法表:虚方法表会在类加载的连接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM会把该类的方法表也初始化完毕。