深入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相关操作码 的相关文章

随机推荐

  • 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 其中 方法调用相关的操作码为