JVM学习-动态链接和方法返回地址

动态链接–指向运行时常量池的方法引用
  • 每一个栈帧内部包含一个指向运行时常量池中该栈帧所属方法的引用,包含这个引用的目的为了支持当前方法的代码能够实现动态链接(Dynamic Linking),如invokednamic指令。
  • 在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用保存在class文件的常量池中,比如一个方法调用了另一个方法,就是通过常量池中方法的符号引用来表示的,动态链接的作用是为了将这些符号引用转换为调用方法的直接引用。
    在这里插入图片描述
为什么需要常量池?

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

方法的调用

在JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制相关,绑定机制分为早期绑定和晚期绑定,绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。

  • 早期绑定:指被调用的目标方法如果在编译期可知,且运行期保持不变时,即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也可以使用静态链接的方式将符号引用转换为直接引用
  • 晚期绑定:如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,称为晚期绑定
静态链接

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

动态链接

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

class Animal {public void eat(){System.out.println("动物进食");}
}
interface Huntable {void hunt();
}
class Dog extends Animal implements Huntable {@Overridepublic void eat() {System.out.println("狗吃骨头");}@Overridepublic void hunt() {System.out.println("狗拿耗子,多管闲事");}
}
class Cat extends Animal implements Huntable {public Cat() {super();   //早期绑定}public Cat(String name) {this();    //早期绑定}@Overridepublic void eat() {super.eat();       //早期绑定System.out.println("猫吃鱼");}@Overridepublic void hunt() {System.out.println("猫拿耗子,天经地义");}
}
public class AnimalTest {public void showAnimal(Animal animal) {animal.eat(); //晚期绑定}public void showHunt(Huntable h) {h.hunt(); //晚期绑定}
}
虚方法和非虚方法
  • 非虚方法:方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的,这种方法称为非虚方法。

  • 静态方法、私有方法、final方法、实例构造器、父类方法都是非虚方法。

  • 其它方法为虚方法

  • 普通调用指令

    • invokestatic:调用静态方法,解析阶段确定唯一方法版本
    • invokespecial:调用方法,私有及父类方法,解析阶段确定唯一方法版本
    • invokevirtual:调用所有虚方法
    • invokeinterface:调用接口方法
  • 动态调用指令

    • invokedynamic:动态解析出需要调用的方法,然后执行
      普通调用指令固化在虚拟机内部,方法的调用执行不可人为干预,而invokedynamic指令则支持由用户确定方法版本,其中invokestatic指令和invokespecial指令调用的方法称为非虚方法,其余的(final修饰的除外)称为虚方法
      静态类型语言是判断变量自身的类型信息,动态类型语言是判断变量值的类型信息,变量没有类型信息,变量值才有类型信息。
class Father {public Father() {System.out.println("father构造器");}public static void showStatic(String str) {System.out.println("father " + str);}public final void showFinal() {System.out.println("father show final");}public void showCommon() {System.out.println("father 普通方法");}
}
public class Son extends Father{public Son() {super();}public Son(int age) {this();}//非重写父类的方法,静态方法不允许重写public static void showStatus(String str) {System.out.println("son " + str);}private void showPrivate(String str) {System.out.println("son private " + str);}public void show() {//invokestaticshowStatic("lotus.com");//invokestaticsuper.showStatic("goods!");//invokespecialshowPrivate("hellow!");//invokespecialsuper.showCommon();//invokevirtual,此方法声明有final,不能被子类重写,此方法为非虚方法showFinal();//invokevirtualshowCommon();info();MethodInterface in = null;//invokeinterfacein.methodA();}private void info() {}public void display(Father f) {f.showCommon();}public static void main(String[] args) {Son so = new Son();so.show();}
}
interface MethodInterface {void methodA();
}
@FunctionalInterface
interface Func {public boolean func(String str);
}
public class Lambda {public void lambda(Func func) {return;}public static void main(String[] args) {Lambda lambda = new Lambda();//invokedynamicFunc func = s-> {return true;};//invokedynamiclambda.lambda(s-> {return true;});}
}
方法重写本质
  1. 找到操作数栈顶的第一个元素所执行的对象的实际类型,记作C
  2. 如果过程结束,不通过类型C中找到与常量中的描述符符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找不到,则返回java.lang.IllegalAccessError异常
  3. 否则,按继承关系从下向上依次对C的各个父类进行第2步搜索和验证过程
  4. 如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。
虚方法表
  • 在面向对象的编程中,会频繁的使用到动态分派,如果在每次动态分派的过程中都要重新在类的方法元数据中搜索合适的目标的话,就可能影响到执行效率,因此,为了提高性能,JVM采用在类的方法区建立一个虚方法表(非虚方法不会出现在表中)来实现,使用索引表代替查找
  • 每个类中都有一个虚方法表,表中存放各个方法的实际入口
  • 虚方法表会在类加载的链接阶段被创建并开始初使化,类的变量初使值准备完成之后,JVM会把该类的方法一也初始化完毕
方法返回地址
  • 存放调用该方法的PC寄存器的值
  • 一个方法结束,有两种方式:
    • 正常执行完成
      • 一个方法在正常调用完成之后究竟需要使用哪一个返回指令还需要根据方法返回值的实际数据类型而定
      • 在字节码指令中,返回指令包含ireturn(当返回值是boolean,byte,char,short,int类型时),lreturn,freturn,dreturn以及areturn,另外还有一个return指令供声明为void方法,实例化初始化方法、类和接口的初始化方法使用。
    • 出现未处理的异常,非正常退出
      • 方法执行过程中抛出异常时的异常处理,存储在一个异常处理表,方便在发生异常的时候找到处理异常的代码。
  • 无论哪种方式退出,在方法退出后都返回到该方法被调用的位置,方法正常退出时,调用者PC寄存器的值做为返回地址,好调用该方法的指令的下一条指令地址,而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;/*** Administrator* 2024/5/17*/
public class ReturnAddressTest {//ireturnpublic boolean methodBoolean() {return false;}//ireturnpublic byte methodByte(){return 0;}//ireturnpublic short methodShort(){return 0;}//ireturnpublic char methodChar(){return 'a';}//ireturnpublic int methodInt(){return 0;}//lreturnpublic long methodLong(){return 0L;}//freturnpublic float methodFloat(){return 0.0f;}//dreturnpublic double methodDouble(){return 0.0;}//areturnpublic String methodString() {return null;}//areturnpublic Date methodDate(){return null;}//returnpublic void methodVoid(){}static {int i = 10;}public void method2() {methodVoid();try {method1();} catch (IOException e) {e.printStackTrace();}}public void method1() throws IOException {FileReader fr = new FileReader("lotus.txt");char[] cBuffers = new char[1024];int len;while ((len = fr.read(cBuffers))!=-1) {String str = new String(cBuffers,0,len);System.out.println(str);}fr.close();}public static void main(String[] args) {}
}

方法返回地址本质上,方法的退出就是当前栈帧出栈的过程,此时,需要恢复上层方法的局部变量表、操作数栈、将返回值压入调用者栈帧的操作数栈、设置PC寄存器值等,让调用者方法继续执行下去

正常完成出口和异常完成出口区别:通过异常完成出口退出的不会给他的上层调用者产生任何返回值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/14362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA:浅谈JSON与JSON转换

可能有很多人,无论是前端还是后端,无论是JAVA还是Python还是C,都应该跟JSON这种数据格式打过交道,那么有没有仔细的想过,什么叫JSON? JSON是一种轻量级的数据交换格式。它基于JavaScript语言的对象表示法&a…

初识java——javaSE(6)抽象类与接口【求个关注!】

文章目录 前言一 抽象类1.1 抽象类的概念1.2 抽象类的语法:1.3 抽象类与普通类的区别: 二 接口2.1 接口的概念2.2 接口的语法2.2.1 接口的各个组成2.2.2 接口之间的继承 2.3 接口的实现接口不可以实例化对象 2.4 接口实现多态 三 Object类3.1 Object类是…

第17讲:C语言内存函数

目录 1.memcpy使用和模拟实现2.memmove使用和模拟实现3.memset函数的使用4.memcmp函数的使用 1.memcpy使用和模拟实现 void * memcpy (void * destination, const void * source, size_t num);• 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存…

网络安全技术与应用:远程控制与数据库安全

实验准备 软件:VMware Workstation Pro 虚拟机:Red Hat Enterprise Linux 7 服务器,Red Hat Enterprise Linux 7 客户端 网络模式:NAT模式 1、配置服务器及客户端网络 服务器IP 客户端IP 测试相互通信 在客户机上设置镜像&#…

车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文

系列文章目录 车载网络测试实操源码_使用CAPL脚本解析hex、S19、vbf文件 车载网络测试实操源码_使用CAPL脚本对CAN报文的Counter和CRC进行实时监控 车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文 车载网络测试实操源码_使用CAPL脚本实现安全…

利用神经网络学习语言(四)——深度循环神经网络

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型:从线性回归到通用人工智能》,欢迎有兴趣的读者多多支持。 本文涉及到的代码链接如下:regression2chatgpt/ch10_rnn/char_rnn_batch.ipynb 《循环神经网络(RNN&…

【移花接木】OpenCV4.8 For Java 深度学习 实时人脸检测

学习《OpenCV应用开发:入门、进阶与工程化实践》一书,学会本文所有技能就这么简单! 做真正的OpenCV开发者,从入门到入职,一步到位! 前言 我写这篇文章之前,我搜索整个网络文章跟问各种语言大模…

速卖通测评揭秘:如何选择安全的渠道操作

许多商家对测评存在误解,认为只需进行几次测评就能迅速打造爆款。实际上,测评是一个需要计划和持久性的过程,以便让平台检测到产品的受众程度并提高产品的曝光和权重。 在进行测评时,安全是首要考虑的问题。平台可以通过设备、网…

黑马点评1——短信篇(基于session)

🌈hello,你好鸭,我是Ethan,一名不断学习的码农,很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 🏃人生之义,在于追求,不在成败,勤通…

如何使用多种算法解决LeetCode第135题——分发糖果问题

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…

Ubuntu中 petalinux 安装 移植linux --tftp/tftp-hpa服务的方法

Xilinx 文档 PetaLinux 指南:如何创建 PetaLinux 环境 (2019.1) PetaLinux工具参考指南 PetaLinux安装详解(Xilinx , linux, zynq, zynqMP) petalinux 2020.1安装教程 一、PetaLinux工具和库安装 PetaLinux 工具要求主机系统 /bin/sh 为“b…

笔记 | 《css权威指南》

网络安全色 URL text-indent line-height & vertical-align 字体 font-weight 400 normal 700 bold background-attachment

【调试笔记-20240516-Windows-使用VS2019编译edk2(上)】

调试笔记-系列文章目录 调试笔记-20240516-Windows-使用VS2019编译edk2(上) 文章目录 调试笔记-系列文章目录调试笔记-20240516-Windows-使用VS2019编译edk2(上) 前言一、安装开发工具1. 安装 VS20192. 安装 Python 3.103. 安装 …

pdf加水印怎么加?3种添加水印方法分享

pdf加水印怎么加?PDF加水印不仅是为了保护文档内容,确保信息的安全性和完整性,更是一种有效的版权保护措施。通过添加水印,您可以在文档中嵌入公司名称、日期、编号等信息,以明确文档的归属权和使用限制。此外&#xf…

小而美:两步完成从源码到应用的极简交付

作者:花三(王俊) Serverless 应用引擎 SAE 是阿里云推出的一款零代码改造、极简易用、自适应弹性的容器化应用托管平台,面市以来为几万家企业客户提供服务,运行稳定,广受好评。 SAE 的出现解决了众多企业…

运行时异常和编译时异常的区别

Java中的异常被分为两大类:编译时异常和运行时异常。 都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException。这些异常是不检查异常,运行时异常的特点是Java编译器不会检查它,程序中可以选择捕…

纯代码如何实现WordPress搜索包含评论内容?

WordPress自带的搜索默认情况下是不包含评论内容的,不过有些WordPress网站评论内容比较多,而且也比较有用,所以想要让用户在搜索时也能够同时搜索到评论内容,那么应该怎么做呢? 网络上很多教程都是推荐安装SearchWP插…

Spring Web MVC介绍及详细教程

目录 1.什么是Spring Web MVC? 1.1 MVC定义 1.2 Spring MVC与MVC关系 2.为什么要学习Spring MVC 3.项目创建 4.Spring MVC连接 4.1 RequestMapping 4.2 PostMapping和GetMapping 5.Spring MVC参数获取 5.1 获取单个参数 5.2 获取多个参数 5.3 获取普通对…

通用代码生成器应用场景一,项目前期

通用代码生成器是一种自动化编程软件,是一种先进的编译系统。它具有表级抽象。把系统抽象为域对象,枚举,弹性登录模块,复杂版面和图形报表。使用通用代码生成器完成项目前期,比直接使用对应的高级语言快的多&#xff0…

element Notification 消息过多需要折叠

Notification 消息过多太长 希望能折叠 如图下效果 element-plus 可以将dom 插入到具体的元素 结合css :nth-child 来控制样式达到效果 element dom 只能插入到body中 所以无法使用:nth-child 1.Notification需要消息提示时设置class let eleNum 0 // 弹窗的序号 function…