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,一经查实,立即删除!

相关文章

云平台概要设计文档 -大纲

1. 引言 1.1 目的 本文档的目的是提供一份详细的技术规范,用以指导开发团队实现云平台的建设和部署。该文档旨在确保所有开发人员和相关技术人员对系统的架构、组件、交互流程、数据处理及安全措施有深入的理解,从而能够高效、一致地开发出符合预期功能和性能要求的系统。 …

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类是…

【shell】脚本练习题

案例: 1. for ping测试指网段的主机 网段由用户输入,例如用户输入192.168.2 ,则ping 192.168.2.10 --- 192.168.2.20 UP: /tmp/host_up.txt Down: /tmp/host_down.txt 2. 使用case实现成绩优良差的判断 1. for ping测试指…

Android异常及解决方式记录

异常1:Tmp detached view should be removed from RecyclerView before it can be recycled: 解决方法: recycleView.setItemAnimator(null);

第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指向的内存…

Python面试宝典:Python中与多线程编程相关的面试笔试题(1000加面试笔试题助你轻松捕获大厂Offer)

Python面试宝典:1000加python面试题助你轻松捕获大厂Offer【第二部分:Python高级特性:第十三章:并发编程:第一节:多线程编程】 第十三章:并发编程第一节:多线程编程使用`threading`模块面试题1面试题2面试题3面试题4面试题5面试题6面试题7面试题8面试题9面试题10更多面…

打豆豆game

好的,我将为您编写一个简单的“打豆豆”游戏。这个游戏的基本规则是这样的: 游戏将生成一个指定大小的网格,每个格子可能包含一个豆豆。玩家可以指定一个格子,如果该格子中有豆豆,则打掉该豆豆,并得分。每…

【Java 开发】模版模式使用模版

在日常开发中,对适合的场景。使用模板模式可以帮助我们抽取公共的东西,使代码更加优雅。本次写了一个模版模式的使用模版,方便以后 cv。 本次是以订单的接受、拒绝、关闭三个操作作为 demo 来写的模板。 一、定义请求基类,不同操作…

leecode42 DP

自己的暴力想法,把图形看成一个个碗,一段一段地算,错误示例 class Solution { public:int trap(vector<int>& height) {int s height.size();int sum 0,kk1;int flag 0;int p1 -1, p2 -1;for (int i 1; i < s; i) {cout<<p1<<endl;if (p1 >…

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

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

【C++刷题】优选算法——递归第二辑

全排列 vector<vector<int>> vv; void dfs(vector<int>& nums, vector<int>& v, vector<bool>& check) {if(v.size() nums.size()){vv.push_back(v);return;}for(int i 0; i < nums.size(); i){if(check[i] false){v.push_ba…

pillow学习5

ImageEnhance 模块 内置的 ImageEnhance 模块中包含了多个用于增强图像效果的函数&#xff0c;主要用来调整图像 的色彩、对比度、亮度和清晰度等&#xff0c;感觉上和调整电视机的显示参数一样。 在模块 ImageEnhance 中&#xff0c;所有的图片增强对象都实现一个通用的接口。…

nginx的配置以及常见命令

Nginx配置与常用命令指南 Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP服务器。由于它的稳定性、丰富的功能集、简单的配置文件和低资源消耗&#xff0c;Nginx在全球范围内被广泛使用。在本文中&#xff0c;我们将介绍Nginx的基本配置和一些常…

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

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

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

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

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

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

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

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

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

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

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

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