JAVA语言多态和动态语言实现原理

JAVA语言多态和动态语言实现原理

  • 前言
  • invoke指令
    • invokestatic
    • invokespecial
    • invokevirtual
    • invokeinteface
    • invokedynamic
    • Lambda
  • 总结

前言

我们编码java文件,javac编译class文件,java运行class,JVM执行main方法,加载链接初始化对应类,确定类/对象调用函数,执行对应函数方法code字节码,执行引擎不断取指执行。本文主要介绍虚拟机加载链接初始化类后,在执行函数调用时虚拟机如何通过相关invoke指令,确定具体执行函数,并以此介绍JAVA语言中多态和动态语言实现原理。

invoke指令

虚拟机再实现函数调涉及invoke指令,分为如下5类:

invoke指令函数调用
invokestatic执行类静态方法
invokespecial执行对象构造器,私有方法,父类方法
invokevirtual执行类对象的普通方法,(非静态,构造器,私有方法等),
虚拟机在运行期通过动态分派
invokeinterface接口对象执行接口方法,虚拟机在运行期通过动态分派
invokedynamic用户编码确定方法句柄

下面代码分别演示编译后函数调用使用invoke指令,使用jclasslib idea插件查看:

public class InvokeTestDemo extends AbsParent implements InterfaceParent {public static void main(String[] args) throws Throwable{InvokeTestDemo demo = new InvokeTestDemo();demo.test();}private void test() throws Throwable{// invokestatic 静态方法staticMethod();// invokespecial 构造方法new InvokeTestDemo();// invokespecial 私有方法privateMethod();// invokespecial 父类方法, 内部super.parentMethod();// invokevirtualfinalMethod();publicMethod();parentMethod();interfaceMethod();// invokeinterface 接口方法InterfaceParent iTest = this;iTest.interfaceMethod();// invokedynamicFunction<String, String> func = str -> "append " + str;func.apply("test");// MethodHandleAnimal animal = new Animal();say(animal);People people = new People();say(people);}public static void say(Object obj) throws Throwable {MethodHandles.Lookup lookup = MethodHandles.lookup();MethodType methodType = MethodType.methodType(void.class);MethodHandle methodHandle = lookup.findVirtual(obj.getClass(), "say", methodType);methodHandle.invoke(obj);}public static class Animal {public void say() {System.out.println("hello Animal");}}public static class People {public void say() {System.out.println("hello People");}}public static void staticMethod() {}private void privateMethod() {}public final void finalMethod() {}public void publicMethod() {}@Overridepublic void interfaceMethod() {}
}abstract class AbsParent {public void parentMethod() {}
}interface InterfaceParent {void interfaceMethod();
}

invokestatic

调用类静态方法,属于静态分派,编译期可确定调用方法,运行期不变。
静态方法调用

invokespecial

调用对象构造器,私有方法,直接父类方法,属于静态分派,编译期可确定调用方法,运行期不变。
构造函数私有方法父类方法

invokevirtual

调用对象普通方法(非对象构造器,私有方法,直接父类方法),运行期根据对象具体类型,再确定具体执行方法,这个便是语言多态特征。
可重写方法

在具体实现上,以HotSpot为例,HotSpot使用了与C++虚函数类似的机制,同时为了避免每个对象都维护一个虚函数表,设计了Oop-Klass模型,用Klass类保存类的元数据和虚函数表vtable (virtual method table)。
vtable生成:
1、递归生成父类vtable
2、覆盖重写方法
3、追加新定义方法

Class Animal {public void breathe() {}public void sound() {}}Class Cat extends Animal{@overridepublic void sound() {}public void run() {}
}

Animal vtable

方法方法地址
breathe@Animal#breathe
sound@Animal#sound

Cat vtable

方法方法地址备注
breathe@Animal#breathe取自父类
sound@Cat#sound本类重写
sound@Cat#run本类追加

vtable是用空间换取时间,类对应klass维护相对应的vtable,发生函数调用时,操作步骤如下:
1、通过函数操作数栈,获取栈顶调用函数者。
2、函数调用者查找实际类型class,进而确定klass关联vtable。
3、通过函数编号,找到vtable函数编号的方法代码code。
4、读取code字节码指令,执行引擎执行指令。

invokeinteface

以接口调用接口类方法,运行期根据接口实现类型,再确定具体执行方法。
接口方法

在具体实现上,以HotSpot为例,同vtable实现类似,接口是使用itable(inteface method table)实现方法动态分派。

itable存储格式如下:
itableOffsetEntry1
itableOffsetEntry2
……
itableOffsetEntryn
itableMethodEntry1
itableMethodEntry2
……
itableMethodEntryn

itable函数查找过程如下:
1、通过函数操作数栈,获取栈顶调用函数者。
2、函数调用者查找实际类型class,进而确定klass关联itable。
3、遍历itable查找接口entry对应itableOffsetEntry。
4、通过itableOffsetEntry

为什么需要itable,而不是用vtable去实现:
1、一个类继承是单继承,子类包含父类vtable,且和父类的函数编号是一致,可以直接使用父类的函数编号找到对应的子类实现函数。
2、一个类可以实现多个接口,而每个接口的函数编号是个接口相关,vtable无法解决多个对应接口的函数编号问题。
即:虚拟机规范规定,继承是单继承,实现是可实现多个接口。

invokedynamic

以上介绍invoke指令调用的函数流程实现是在虚拟机内部,编译器和虚拟机运行期完成调用方法查找并执行相应字节码,而invokedynamic指令则支持由用户编码确定方法句柄,具体查找过程如下:
1、JVM执行到invokedynamic指令时,它会首先查找与该指令关联的引导方法。
2、引导方法根据传入的参数动态生成和链接目标方法,并返回CallSite对象(封装了目标方法的所有信息,包括方法句柄、参数类型和返回类型)。
3、CallSite对象被创建并返回给invokedynamic指令,JVM就会将该指令与调用站点对象关联起来。
4、在后续的执行过程中,当再次遇到相同的invokedynamic指令时,JVM会直接通过调用站点对象调用目标方法,而无需再次执行引导方法。这种机制可以显著提高动态方法调用的性能。

某种意义上可以说invokedynamic指令与MethodHandle机制的作用是一样的。都是为了解决原有的4条”invoke”指令方法分派规则完全固化在虚拟机之中的问题。如何把查找目标方法的决定权从虚拟机转嫁到具体的用户代码中。

Lambda

lambda实现依赖invokedynamic执行,由编译器生成引导方法,生成调用点。

 invokedynamic #13 <apply, BootstrapMethods #0>

lambda引导方法
引导方法

过程如下:
1、Lambda 表达式解析常用引导方法,java.lang.invoke.LambdaMetafactory#metaFactory:
2、引导方法 metaMethod 根据这些参数生成 java.lang.invoke.CallSite 动态调用点
3、在引导方法中会动态生成一个模板匿名类
4、创建匿名类实例,执行方法调用。

总结

多态特性:虚拟机在运行时通过动态分派,查找确定要执行函数。
动态语言:虚拟机通过invokedynamic执行,由应用程序指定MethodHanle,确定函数调用者,方法,参数,调用方法等,实现动态语言。

参考: https://blog.csdn.net/weixin_47184173/article/details/109903542

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

技术星河中的璀璨灯塔 —— 青云交的非凡成长之路

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

Chromium127编译指南 Linux篇 - 额外环境配置(五)

引言 在成功获取 Chromium 源代码后&#xff0c;接下来我们需要配置适当的编译环境&#xff0c;以便顺利完成开发工作。本文将详细介绍如何设置 Python 和相关的开发工具&#xff0c;以确保编译过程无碍进行。这些配置步骤是开发 Chromium 的必要准备&#xff0c;确保环境设置…

基于华为atlas环境下的OpenPose人体关键点检测的人员跨越、坐立检测

整体思路&#xff1a; 收集数据集&#xff0c;数据集中包含3种类型的数据&#xff0c;分别是跨越、坐立、其他&#xff08;站立、睡着等等&#xff09;。3种类型的数据样本量持平。 首先基于OpenPose进行人体关键点的检测&#xff0c;得到人体的18个关键点。然后基于该算法将…

ubuntu20.04 加固方案-设置限制su命令用户组

一、编辑/etc/pam.d/su配置文件 打开终端。 使用文本编辑器&#xff08;如vim&#xff09;编辑/etc/pam.d/su文件。 vim /etc/pam.d/su 二、添加配置参数 在打开的配置文件的中&#xff0c;添加以下参数&#xff1a; auth required pam_wheel.so 创建 wheel 组 并添加用户 …

迅为itop-3568开发板AMP双系统使用手册之烧写AMP镜像

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

2024 年最佳解压缩软件免费下载推荐

在如今的信息时代&#xff0c;解压缩软件对于处理各种压缩文件至关重要。随着互联网的飞速发展&#xff0c;我们在日常工作和生活中会接触到大量的文件&#xff0c;而很多时候这些文件会以压缩的形式进行传输和存储。 对于个人用户而言&#xff0c;解压缩软件能够帮助我们轻松…

MySQL数据库之存储过程的创建与应用

存储过程 procedure 一.存储过程 作用&#xff1a;将经常使用的功能写成存储过程&#xff0c;方便后续重复使用。 二.创建存储过程 三.调用存储过程 call在计算机中是调用的意思 案例1&#xff1a;查看MySQL用户数 如上图所示&#xff0c;这是查看MySQL数据库中的user个数…

JAVA:数据库(mysql)编程初步学习\JDBC(附带项目文件)

给入门的同学初步了解JDBC&#xff0c;本人学疏才浅也希望可以给新人启发&#xff0c;编程的函数比较简单没有用更多库&#xff0c;方便给新人一个舒适的理解 tips&#xff1a;附带编程全套的代码&#xff0c;欢迎大家自由使用,仅供学习&#xff01; &#xff08;文件代码几千…

网页上视频没有提供下载权限怎么办?

以腾讯会议录屏没有提供下载权限为例&#xff0c;该怎么办呢&#xff1f; 最好的办法就是找到管理员&#xff0c;开启下载权限。如果找不到呢&#xff0c;那就用这个办法下载。 1.打开Microsoft Edge浏览器的扩展 2.搜索“视频下载”&#xff0c;选择“视频下载Pro” 3.点击“…

第15课 算法(下)

掌握冒泡排序、选择排序、插入排序、顺序查找、对分查找的的基本原理&#xff0c;并能使用这些算法编写简单的Python程序。 一、冒泡排序 1、冒泡排序的概念 冒泡排序是最简单的排序算法&#xff0c;是在一列数据中把较大&#xff08;或较小&#xff09;的数据逐次向右推移的…

USB摄像头使用V4L2采集图像\视频

背景 V4L2&#xff08;Video for Linux Two&#xff09;是Linux内核自带的一部分&#xff0c;专门用于处理视频设备的管理和控制。‌ V4L2框架提供了统一的API和抽象层&#xff0c;使得开发者可以编写通用的视频驱动程序&#xff0c;同时使用户空间的应用程序能够轻松地访问和…

栈和队列(三)

队列的链式存储表示和实现 链队的类型定义 typedef struct qnode{char data;struct qnode *next; }qnode,*queneptr;typedef struct{queneptr front;queneptr rear; }linkqueue; typedef struct qnode{}&#xff1a; 定义了一个名为qnode的结构体。结构体成员包括&#xff1a…

vmvare启动freebsd操作系统密码忘记了怎么办?

本章教程,主要介绍,通过vmvare安装的freebsd操作系统,密码忘记了,如何重置密码。 一、重启虚拟机 在重启过程中,按键盘中是数字2,进入单用户模式。 二、进入到shell界面 在出现“Enter full pathname of shell or RETURN for /bin/sh:”直接按回车键。 三、输入命令 mou…

设计模式之结构型模式---装饰器模式

目录 1.概述2.类图3.应用场景及优缺点3.1 应用场景3.2 优缺点3.2.1 优点3.2.2 缺点 4.实现4.1 案例类图4.2 代码实现4.2.1 定义抽象构建角色4.2.2 定义具体构建角色4.2.3 定义抽象装饰器角色4.2.4 定义具体装饰角色4.2.5 装饰器模式的使用 1.概述 装饰器模式是指在不改变现有对…

SQL,力扣题目1709,访问日期之间最大的空档期

一、力扣链接 LeetCode_1709 二、题目描述 表&#xff1a; UserVisits ------------------- | Column Name | Type | ------------------- | user_id | int | | visit_date | date | ------------------- 该表没有主键&#xff0c;它可能有重复的行 该表包含用户访问…

极市平台 | NeurIPS 2024|浙大/微信/清华提出:彻底解决扩散模型反演问题

本文来源公众号“极市平台”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;NeurIPS 2024&#xff5c;浙大/微信/清华提出&#xff1a;彻底解决扩散模型反演问题 极市导读 本文介绍了浙江大学、微信和清华大学联合提出的BELM算法…

心觉:人每日60000念头,如何让你的时间精力只专注于核心目标?

Hi&#xff0c;我是心觉&#xff0c;带你用潜意识化解各种焦虑、内耗&#xff0c;建立无敌自信&#xff1b;教你财富精准显化的实操方法&#xff1b;关注我,伴你一路成长&#xff01; 每日一省写作220/1000天 据说一个人每天会产生60000个念头 有些我们的意识能察觉到&#x…

89.冒泡算法(代码编写)

目录 一.代码编写 二.视频教程 一.代码编写 #include <stdio.h>void main(void) {int data[10];int j,i;int temp;printf("Please input data:\n");for(i0;i<10;i){scanf("%d",&data[i]);}for(i0;i<10;i){for(j0;j<9-i;j){if(data[j…

SQL CASE表达式与窗口函数

CASE 表达式是一种通用的条件表达式&#xff0c;类似于其他编程语言中的if/else语句。 窗口函数类似于group by&#xff0c;但是不会改变记录行数&#xff0c;能扫描所有行&#xff0c;能对每一行执行聚合计算或其他复杂计算&#xff0c;并把结果填到每一行中。 1 CASE 表达式…

ubuntu22-安装vscode-配置shell命令环境-mac安装

文章目录 1.安装vscode2.修改语言为中文3.配置bash调试环境3.1.安装插件3.2.添加配置文件 4.调试bash4.1.新建tmp.sh文件4.2.运行启动 5.mac安装6.mac卸载 1.安装vscode 从官网下载安装包Code_1.93.1-1726079302_amd64.deb。 在ubuntu系统中&#xff0c;安装包所在目录打开命令…