JVM系列-方法调用的原理
JVM系列-方法调用的原理
最近重新看了一些JVM方面的笔记和资料,收获颇丰,尤其解决了长久以来心中关于JVM方法管理的一些疑问。下面介绍一下JVM中有关方法调用的知识。
目的
方法调用,目的是选择方法正确的执行版本,也就是找到方法的入口地址。
方法调用指令
方法调用的字节码指令一共有五种,分别是:
- invokestatic:
- 类方法:static
- invokespecial:
- 方法:实例构造器
- 私有方法:private
- 父类中的方法
- invokevirtual
- 虚方法
- final修饰的方法
- invokeinterface
- 接口方法
- invokedynamic
- 用于动态语言支持
方法分类
非虚方法:
- 特点:
- 在类加载时期,有些方法的调用版本已经能够确定,在类加载-解析阶段,把这些方法的符号引用替换为直接引用(即入口地址)。
- 包括:
- 类方法
- 方法
- 私有方法
- 父类中的方法
- final方法
即由invokestatic、invokespecial指令调用的方法,以及final修饰的方法,属于非虚方法
虚方法:
- 特点:
- 在类加载时期,无法确定方法最终的调用版本
- 包括:
- 非非虚方法
即由invokevirtual调用的方法,除了final修饰的之外,都是虚方法
调用方式
解析
- 定义:对于非虚方法,在类加载的时候已经能确定这些方法的调用版本,在类加载的解析阶段把符号引用替换为直接引用,就是方法的入口地址
- 范围:非虚方法
分派
静态分派
- 定义:在编译期,根据方法涉及的引用类型(包括参数列表的引用类型和方法的调用者的引用类型)来确定方法调用的(初步)版本,并把相应的符号引用放在字节码指令中,这个步骤叫做静态分派
- 范围:虚方法、非虚方法
- 应用:方法的重载
动态分派
- 定义:在运行时,根据对象的实际类型来确定方法的调用版本,这个步骤叫做动态分派
- 范围:虚方法
- 应用:方法的重写
- 原理:
- 方法调用的部分字节码指令:
- aload:在调用方法时,总是有该指令将实际类型的对象引用入栈
- 加载方法参数
- invoketual
- 先在栈顶取到实际类型的对象引用
- 根据方法的符号引用在本类中寻找,找不到的话依次向上在父类中找该方法
- 优化实现:在虚拟机中,虚方法表是动态分派的一种优化实现
- 虚方法表:
- 定义:类信息的一种,在类加载-准备阶段完成初始化,存放在方法区
- 特点:
- 虚方法表中存储方法的入口地址
- 子类中继承但未重写的方法,在子类的虚方法表中存放的入口地址,就是父类的虚方法表中的入口地址,指向父类的实现
- 在父子类中,相同符号引用的方法(重写)的方法,其在各自虚方法表中的索引相同
- 解释动态分派:
- 根据字节码指令的符号引用,找到该方法在父类虚方法表中的索引
- 切换到实际类型的虚方法表,通过该索引,找到方法的入口地址
- 虚方法表:
- 方法调用的部分字节码指令:
总结
主要内容在于方法调用的方式,即如何找到方法的入口地址的过程。
在这三种方式中,静态分派发生在编译期,解析发生在类加载时,动态分派发生在运行时。针对三者作用对象的不同可知,静态分派是可以和解析或动态分派同时发生的,如类方法依然可以重载,重写的方法也可以重载。但解析和动态分派是不可共存的。
以上是我的分享,如有疑问或错误,请指出,一起学习。
参考
《深入理解Java虚拟机_JVM高级特性与最佳实践-第3版》
JVM系列-方法调用的原理的更多相关文章
- 深入探究JVM之方法调用及Lambda表达式实现原理
@ 目录 前言 正文 解析 分派 静态分派 动态分派 单分派和多分派 动态分派的实现 Lambda表达式的实现原理 MethodHandle 总结 前言 在最开始讲解JVM内存结构的时候有简单分析过方 ...
- 以方法调用的原理解释Ruby中“puts ‘Hello‘”
这里尽管缺少消息发送所需要的点(.)以及该消息的显示接收者,却依然发送了消息puts并传递了参数“Hello”给一个对象:默认对象self.在程序运行期间,虽然作为self的对象通过特定规则发生改变, ...
- Spring杂谈 | 从桥接方法到JVM方法调用
前言 之所以写这么一篇文章是因为在Spring中,经常会出现下面这种代码 // 判断是否是桥接方法,如果是的话就返回这个方法 BridgeMethodResolver.findBridgedMetho ...
- Java方法调用机制
最近在编程时,修改方法传入对象的对象引用,并没有将修改反映到调用方法中.奇怪为什么结果没有变化,原因是遗忘了Java对象引用和内存分配机制.本文介绍3个点: ① 该问题举例说明 ② 简要阐述Java内 ...
- 聊聊 C# 中的多态底层 (虚方法调用) 是怎么玩的
最近在看 C++ 的虚方法调用实现原理,大概就是说在 class 的首位置存放着一个指向 vtable array 指针数组 的指针,而 vtable array 中的每一个指针元素指向的就是各自的 ...
- JVM方法调用
当我们站在JVM实现的角度去看方法调用的时候,我们自然会想到一种分类: 1.编译代码的时候就知道是哪个方法,永远不会产生歧义,例如静态方法,private方法,构造方法,super方法. 2.运行时才 ...
- java方法调用之动态调用多态(重写override)的实现原理——方法表(三)
上两篇篇博文讨论了java的重载(overload)与重写(override).静态分派与动态分派.这篇博文讨论下动态分派的实现方法,即多态override的实现原理. java方法调用之重载.重写的 ...
- JVM(十二):方法调用
JVM(十二):方法调用 在 JVM(七):JVM内存结构 中,我们说到了方法执行在何种内存结构上执行:Java 方法活动在虚拟机栈中的栈帧上,栈帧的具体结构在内存结构中已经详细讲解过了,下面就让我们 ...
- JAVA的List接口的remove重载方法调用原理
前言 说真的,平常看源码都是自己看完自己懂,很少有写出来的冲动. 但是在写算法的时候,经常用到java中各种集合,其中也比较常用到remove方法. remove有重载函数,分别传入参数是索引inde ...
随机推荐
- LR脚本信息函数-lr_start_timer和lr_end_timer
为了计算时间更加精确,可以用这个函数去掉LR自身的检查点所浪费的时间.如text check and image time Action() { double time_elapsed, durati ...
- Jmeter基础002----Jmeter简单使用
一.Jmeter概述 1.概述 JMeter是Apache公司使用JAVA开发的一款开源测试工具,它的功能强大.高效,可以模拟一些高并发或多次循环等测试场景,使用方便灵活. 2.使用 安装配置java ...
- Hexo快速构建个人小站-Hexo初始化和将项目托管在Github(一)
背景交代 相信每个程序员都有自己做过个人网站,博客之类的项目了,但是现在还在维护吗?反正我前前后后做过2到3个了,维护一段时间后因为一些不可逆的原因(主要是懒)都没有维护了,购买的一些域名和服务器信息 ...
- 在tp5.1中获取所有控制器的文件名和所有控制器下的方法名
我在这块做的是下拉框改变控制器然后ajax去调用获取方法 上代码 private function redController(){//获取当前控制器目录下所有的文件名 $arr=scandir('. ...
- spring源码分析——BeanPostProcessor接口
BeanPostProcessor是处理bean的后置接口,beanDefinitionMaps中的BeanDefinition实例化完成后,完成populateBean,属性设置,完成 初始化后,这 ...
- Java学习笔记7(IO)
IO(输入输出) IO流按照操作数据的不同,分为字节流和字符流,按照数据传输方向分为输入流和输出流. 字节流 计算机中,所有文件都是以二进制(字节)形式存在,IO流中针对字节的输入输出提供了一系列的流 ...
- oracle自定义split分割函数
函数如下: create or replace FUNCTION fn_rme_split(p_str IN VARCHAR2, p_delimiter IN VARCHAR2) RETURN rme ...
- 韩顺刚-tcp报文头协议详细分析第一包数据:序号是0,发送数据的长度是0,因为没有收到对端的数据,所以确认号是0, Syn的标志位设置成1,这里没有发送的数据,只发送TCP的20个字节的头部
TCP报文段首部格式 大部分TCP报文头部都是20个字节,有的数据包要加上选项. 上面一行代表4个字节,源端口和目的端口都是2个字节. TCP协议是面向字节流的协议 TCP是一段一段分块的发送数据的 ...
- Spring声明周期的学习心得
我们首先来看下面的一个案例: 这里是 HelloWorld.java 文件的内容: package com.yiibai; public class HelloWorld { private ...
- 使用反应式关系数据库连接规范R2DBC操作MySQL数据库
1. 简介 三月份已经介绍过R2DBC,它是一种异步的.非阻塞的关系式数据库连接规范.尽管一些NoSQL数据库供应商为其数据库提供了反应式数据库客户端,但对于大多数项目而言,迁移到NoSQL并不是一个 ...