深入JVM - 实例详解invoke相关操作码

2023-11-02

Java虚拟机规范中有一个章节专门列出了操作码助记符, 对应的链接为: Java Virtual Machine Specification: Chapter 7. Opcode Mnemonics by Opcode

其中, 方法调用相关的操作码为:

十进制 十六进制 助记符 说明
182 (0xb6) invokevirtual 调用类的实例方法;
183 (0xb7) invokespecial 调用特殊实例方法; 如构造函数、超类方法,以及private
184 (0xb8) invokestatic 调用静态方法
185 (0xb9) invokeinterface 调用接口方法
186 (0xba) invokedynamic 动态方法调用

下面我们通过实际的例子, 进行详细介绍。

请看代码:

package com.cncounter.opcode;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 演示invoke操作码
 */
public class DemoInvokeOpcode {

  public static void testMethodInvoke() {
      // 183; invokespecial
      HashMap<String, String> hashMap = new HashMap<String, String>(100);
      // 182; invokevirtual
      hashMap.put("name", "tiemao");
      // 赋值给Map接口引用
      Map<String, String> map = hashMap;
      // 185; invokeinterface
      map.putIfAbsent("url", "https://renfufei.blog.csdn.net");
      // 使用lambda
      List<String> upperKeys = map.keySet().stream()
              // 186; invokedynamic
              .map(i -> i.toUpperCase())
              .collect(Collectors.toList());
      // 184; invokestatic
      String str = String.valueOf(upperKeys);
      // 182; invokevirtual
      System.out.println(str);
  }

  public static void main(String[] args) {
      // 184; invokestatic
      testMethodInvoke();
  }
}

执行main方法之后的输出内容为:

[NAME, URL]

我们可以使用以下命令进行编译和反编译:

# 查看JDK工具的帮助信息
javac -help
javap -help

# 带调试信息编译
javac -g DemoInvokeOpcode.java
# 反编译
javap -v DemoInvokeOpcode.class

# 因为带了package, 所以执行时需要注意路径:
cd ../../..
java com.cncounter.opcode.DemoInvokeOpcode

javac编译之后, 可以看到只生成了一个文件 DemoInvokeOpcode.class。 这也是 lambda 与内部类不同的地方。

反编译工具 javap 输出的字节码信息很多, 节选出我们最关心的testMethodInvoke方法部分:

public static void testMethodInvoke();
  descriptor: ()V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=3, locals=4, args_size=0
       0: new           #2                  // class java/util/HashMap
       3: dup
       4: bipush        100
       6: invokespecial #3                  // Method java/util/HashMap."<init>":(I)V
       9: astore_0
      10: aload_0
      11: ldc           #4                  // String name
      13: ldc           #5                  // String tiemao
      15: invokevirtual #6                  // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      18: pop
      19: aload_0
      20: astore_1
      21: aload_1
      22: ldc           #7                  // String url
      24: ldc           #8                  // String https://renfufei.blog.csdn.net
      26: invokeinterface #9, 3            // InterfaceMethod java/util/Map.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      31: pop
      32: aload_1
      33: invokeinterface #10, 1           // InterfaceMethod java/util/Map.keySet:()Ljava/util/Set;
      38: invokeinterface #11, 1           // InterfaceMethod java/util/Set.stream:()Ljava/util/stream/Stream;
      43: invokedynamic #12, 0             // InvokeDynamic #0:apply:()Ljava/util/function/Function;
      48: invokeinterface #13, 2           // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
      53: invokestatic  #14                 // Method java/util/stream/Collectors.toList:()Ljava/util/stream/Collector;
      56: invokeinterface #15, 2           // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
      61: checkcast     #16                 // class java/util/List
      64: astore_2
      65: aload_2
      66: invokestatic  #17                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      69: astore_3
      70: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
      73: aload_3
      74: invokevirtual #19                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      77: return
    LineNumberTable:
      line 15: 0
      line 17: 10
      line 19: 19
      line 21: 21
      line 23: 32
      line 25: 48
      line 26: 53
      line 28: 65
      line 30: 70
      line 31: 77
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
         10      68     0 hashMap   Ljava/util/HashMap;
         21      57     1   map   Ljava/util/Map;
         65      13     2 upperKeys   Ljava/util/List;
         70       8     3   str   Ljava/lang/String;
    LocalVariableTypeTable:
      Start  Length  Slot  Name   Signature
         10      68     0 hashMap   Ljava/util/HashMap<Ljava/lang/String;Ljava/lang/String;>;
         21      57     1   map   Ljava/util/Map<Ljava/lang/String;Ljava/lang/String;>;
         65      13     2 upperKeys   Ljava/util/List<Ljava/lang/String;>;

简单解释如下:

  • 调用某个类的静态方法, 使用的是 invokestatic 指令。
  • 当通过接口引用来调用方法时, 会直接编译为 invokeinterface 指令。
  • 调用构造函数会编译为 invokespecial 指令, 当然还包括调用 private 方法, 以及可见的超类方法。
  • 如果变量引用的类型是具体类, 则编译器会使用 invokevirtual 来调用 public, protected和包可见级别的方法。
  • JDK7新增加了一个 invokedynamic 指令, 用来支持“动态类型语言”(Dynamically TypedLanguage, 从JDK8开始引入的lambda表达式, 在使用时会编译为这个指令。

更多文章请参考GitHub上的文章翻译项目: https://github.com/cncounter/translation

同时也请各位大佬点赞Star支持!

原文链接: 2020年文章: 41.深入JVM - 实例详解invoke相关操作码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入JVM - 实例详解invoke相关操作码 的相关文章

  • 在 Java 中连接和使用 Cassandra

    我已经阅读了一些关于 Cassandra 是什么以及它可以做什么的教程 但我的问题是如何在 Java 中与 Cassandra 交互 教程会很好 如果可能的话 有人可以告诉我是否应该使用 Thrift 还是 Hector 哪一个更好以及为什
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O

随机推荐

  • nginx 报错[emerg]: unknown directive “锘? in E:\nginx-1.18.0/conf/nginx.conf:3

    报错 nginx 报错 emerg 32408 14080 unknown directive 锘 in E nginx 1 18 0 conf nginx conf 3 原因 使用nginx服务时 用txt记事本打开编辑了nginx co
  • 清除浮动的五种方法以及优缺点

    方法一 额外标签法 给谁清除浮动 就在其后额外添加一个空白标签 给其设置clear both 优点 通俗易懂 书写方便 缺点 添加许多无意义的标签 结构化比较差 clear both 本质就是闭合浮动 就是让父盒子闭合出口和入口 不让子盒子
  • Python实例:用Pandas处理表格(简单的增删改查)

    目录 任务描述 实现过程 任务描述 描述 现有一个excel表格 补充SCI模板 其中包括6个子表 中科院1区 表1 JCR Q1 表2 教研室补充 表 CCF A 表 CCF B 表 CCF C 表 每个表格第一列为期刊名称 需要为这些期
  • 基于springboot+vue的网上商城管理系统,附源码+数据库+lw文档+PPT,适合课程设计、毕业设计

    1 项目介绍 在Internet高速发展的今天 我们生活的各个领域都涉及到计算机的应用 其中包括网上图书商城的网络应用 在外国网上图书商城已经是很普遍的方式 不过国内的管理网站可能还处于起步阶段 网上图书商城具有网上图书信息管理功能的选择
  • Visual Studio在Release模式下开启debug调试,编译器提示变量已被优化掉,因而不可用

    系列文章目录 文章目录 系列文章目录 前言 一 解决办法 1 修改工程属性 参考 前言 我们在编写代码的时候 如果用到别人的库 而别人只提供了release版本 所有我们也只能生成release版本的工程 但是 我们又想调试代码 如果我们直
  • vue3 naiveui 自定义v-loading指令

    1 在sr目录下创建loading文件夹 包含index ts和index vue 2 index ts import render VNode createVNode from vue import Loading from index
  • 【Java基础知识 12】java枚举详解

    Java学习路线 搬砖工逆袭Java架构师 简介 Java领域优质创作者 CSDN哪吒公众号作者 Java架构师奋斗者 扫描主页左侧二维码 加入群聊 一起学习 一起进步 欢迎点赞 收藏 留言 目录 一 基本概念 二 枚举的优缺点 1 优点
  • focal loss的几种实现版本(Keras/Tensorflow)

    起源于在工作中使用focal loss遇到的一个bug 我仔细的学习多个靠谱的focal loss讲解及实现版本 通过测试 我发现了这样一个奇怪的现象 几乎每个版本的focal loss实现对同样的输入计算出的loss都是不同的 通过仔细的
  • 吃透Kafka底层通信机制后,我把系统网络性能提升了10倍以上!

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 目录 1 客户端与服务端的交互 2 频繁网络通信带来的性能低下问题 3 batch机制 多条消息打包成一个batch 4 request机制 多个batch打包成一个
  • 使用遗传算法解决旅行商问题

    遗传算法 Genetic Algorithm GA 最早是由美国的 John holland于20世纪70年代提出 该算法是根据大自然中生物体进化规律而设计提出的 是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型 是一种
  • Install and Configure JRebel for MyEclipse

    http www zeroturnaround com jrebel using jrebel with myeclipse utm source jrebelDLpage utm medium idepluginlink utm camp
  • Zabbix 邮件告警

    一 登录邮箱 这里使用126邮箱 http mail 126 com 二 开启POP3的授权码 三 Zabbix服务器与邮箱服务器的连通性测试 root zabbix server nc smtp 126 com t 25 220 126
  • chatgpt赋能python:Python长度转换程序:方便快捷的单位转换工具

    Python长度转换程序 方便快捷的单位转换工具 如果你曾经需要将英寸转换为厘米 或是想知道你的身高在米制和英制中是多少 那么你一定知道这是一个烦人的任务 为了解决这个问题 我们创建了基于Python的长度转换程序 能够帮助你轻松转换任何单
  • wsl2安装及相关编程环境配置

    wsl2的安装及相关环境配置 1 设置 gt 更新和安全 gt 开发者选项 gt 开发人员模式 2 设置 gt 应用 gt 应用和功能 gt 程序和功能 gt 程序和功能 gt 启用或关闭windows功能 gt 适用于linux的wind
  • 编程训练————岛屿数量(C++)

    岛屿数量 题目描述 主要思想 深度优先搜索 广度优先搜索 代码实现 深度优先搜索 广度优先搜索 题目描述 给你一个由 1 陆地 和 0 水 组成的的二维网格 请你计算网格中岛屿的数量 岛屿总是被水包围 并且每座岛屿只能由水平方向或竖直方向上
  • 如何升级numpy的版本

    嗯 如何升级numpy的版本 这是个很火的问题 解决方案如下 在命令下输入pip install U numpy 就可以升级numpy包了 pip install upgrade numpy 这样也可以
  • 统计二叉树中度为1的节点,层序遍历实现

    include
  • 分布式高可靠:负载均衡

    分布式高可靠 负载均衡 前言 什么是负载均衡 服务请求的负载均衡方法 轮询策略 顺序轮询 加权轮询 随机策略 哈希和一致性哈希策略 对比分析 知识扩展 如果要考虑请求所需资源不同的话 应该如何设计负载均衡策略呢 总结 前言 分布式可靠性相关
  • chrome浏览器安装右键翻译插件

    平常打开网页查看相关文章的时候 遇到一些不会的英文单词 可能第一反应是复制英文单词到百度翻译里面 下面为介绍一种直接右键选中英文单词 实现在线翻译的插件 这边用到的是 划词翻译 插件 安装步骤如下 第一步 下载扩展程序插件 链接 https
  • 深入JVM - 实例详解invoke相关操作码

    Java虚拟机规范中有一个章节专门列出了操作码助记符 对应的链接为 Java Virtual Machine Specification Chapter 7 Opcode Mnemonics by Opcode 其中 方法调用相关的操作码为