首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何找个对象(指令)

如何找个对象(指令)

作者头像
shysh95
发布于 2021-02-25 02:47:23
发布于 2021-02-25 02:47:23
30200
代码可运行
举报
文章被收录于专栏:shysh95shysh95
运行总次数:0
代码可运行

假期已经接近尾声了,新的一年废话不多说,直接开干,话说大家今年有没有领”对象“回家,祝有对象的情人节快乐,没有对象的没关系看完这篇文章就知道如何找个”对象“了,相约下一年和下一个情人节,今天主要讲几个指令类型:

  • 对象创建与访问指令
  • 操作数栈管理指令
  • 控制转移指令
  • 方法调用和返回指令
  • 异常处理指令
  • 同步指令

对象创建与访问指令

类实例和数组虽然都是对象,但JVM分别采用不同的指令进行创建,对象创建以后就可以通过访问指令进行访问。

  • 创建类实例:new
  • 创建数组实例:newarray、anewarray、multianewarray
  • 访问类字段(static字段)和实例字段(非static):getfiled、putfiled、getstatic、putstatic
  • 数组元素加载到操作数栈:baload、caload、salod、ialod、lalod、falod、dalod
  • 操作数栈元素加载到数组中:bastore、castore、sastore、iastore、lastore、fastore、dastore
  • 获取数组长度:arraylength
  • 检查类实例类型:instanceof、checkcast
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ClassTest {

    public void checkCast(Object c) {
        System.out.println(c instanceof Integer);
        System.out.println((int)c);
    }
}

关于checkcast指令,如果发生类型强转不匹配,那么将会抛出ClassCastException。

操作数栈管理指令

JVM提供了一些可以直接操作操作数栈的指令:

  • 将栈顶的一个或者两个元素弹出:pop、pop2
  • 复制栈顶的一个或者两个元素并重新压入栈顶:dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2
  • 将操作栈顶的连个元素进行互换:swap
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ClassTest {

    public static long pop2() {
       return 3L;
    }

    public static int pop() {
        return 1;
    }

    public static void main(String[] args) {
        pop();
        pop2();
    }
}

关于pop和pop2的区别主要是,pop弹出一个操作数栈中的一个32位的值,而pop2是弹出一个值,但是该值需要用两个32位来表示,或者弹出两个32位的值。因此由于long类型是64位,所以采用了pop2。

控制转移指令

控制转移指令可以让JVM有条件或者无条件的从指定位置执行程序。

  • 条件分支:ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeg、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne
  • 复合条件分支:tableswitch、lookupswitch
  • 无条件分支:goto、goto_w、jsr、jsr_w、ret

对于boolean、byte、char和short类型的条件分支比较操作,都采用int类型的比较指令来完成,而对于long、float、double类型的条件分支比较操作,则会先执行相应类型的比较运算指令(dcmpg、dcmpl、fcmpg、fcmpl、lcmp),比较运算指令会返回一个整型值到操作数栈中,然后再执行int类型的条件分支比较操作完成分支的跳转。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ClassTest {

    public void compare(long a) {
        if (a > 3) {
            System.out.println("1");
        } else {
            System.out.println("2");
        }
    }
}

我们解释一下compare方法的Code属性(这里我们假设a的值为1):

0:将第一个局部变量压入操作数栈

1:将常量池中第二项元素(3)压入操作数栈顶

2:这里就采用到了比较运算指令lcmp,lcmp会将栈顶的两个元素弹出,如果栈顶的元素大于第二个栈元素,那就将-1压入操作数栈中,如果栈顶额元素等于第二个栈元素,那么就将0压入操作数栈中,如果栈顶元素小于第二个栈元素,那么将1压入操作数栈中。由于我们这边a的值为1,因此会将-1压入操作数栈中

3:下面采用ifle条件分支比较指令,从下图中我们可以得知ifle会将栈顶元素与0比较,只有栈顶元素小于等于0是结果才为true,由于栈顶的元素是-1,因此结果为true,所以指令将会跳转到第19条执行。

19:getstatic是从class中获取一个static属性,这里是PrintStream 22:将常量池中的第7项元素也就是String的2压入操作数栈顶 23:invokevirtual是方法调用指令,用于调用对象的实例方法,这里就是打印2

方法调用和返回指令

  • invokevirtual:调用对象的实例方法
  • invokeinerface:调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找到合适的方法进行调用
  • invokespecial:调用一些特殊处理的实例方法,包括实例初始化方法、私有方法和父类方法
  • invokestatic:调用类方法(静态方法)
  • invokedynamic:用于在运行时动态解析出调用点限定符引用的方法,并执行该方法
  • ireturn:方法返回指令,当返回值是boolean、byte、short、char、int时使用
  • lreturn:返回long类型
  • freturn:返回float类型
  • dreturn:返回double类型
  • areturn:返回reference类型
  • return:方法返回void时候使用

关于invokeddynamic指令下一篇文章中我会以lambda为切入点进行讲解,感兴趣的小伙伴可以关注一下公众号并置顶(防止错过)。

异常处理指令

Java程序中显示抛出异常(throw语句)都由athrow指令来实现。关于catch捕获的异常采用异常表来完成(不清楚的可以阅读一下JVM系列文章)。

同步指令

JVM支持方法级的同步和方法内部一段指令序列的同步,这两种都通过Monitor来实现。

方法级的同步是隐式的,在方法表上,如果一个方法被声明为ACC_SYNCHRONIZED,那么说明这个方法是个同步方法。当方法调用时,执行线程要求先成功持有Monitor,才能执行方法,方法执行完成后,不管是否正常结束都要释放Monitor。在方法执行期间,有且只有一个线程可以获得Monitor。

关于方法内部指令序列的同步通常使用synchronized关键字,JVM通过monitorenter和monitorexit两条指令来支持synchronized关键字。

synchronized关键字需要编译器和JVM两者的共同协作来支持。

编译器需要保证无论通过何种方式,方法中调用过的每条monitorenter指令都必须执行其对应的monitorexit指令。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ClassTest {

    private final Object lock = new Object();

    public void inc(int i) {
        synchronized (lock) {
            i = i + 1;
        }
    }
}

通过我们反编译的字节码序列可以看出,为了保证monitorenter和monitorexit配对执行,编译器自动生成了一个可以处理任何异常的异常处理表,这个异常处理表保证了monitorexit一定被执行。

本期JVM指令就介绍到这,我们下期再见!!!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【JVM进阶之路】十二:字节码指令
在前面的 【JVM进阶之路】三:探究虚拟机对象 里,提到了对象的初始化过程,对象初始化用的是new指令——这就是字节码指令。在【JVM进阶之路】十一:Class文件结构 中已经学习了JVM 字节码是JVM能直接识别的语言,了解了字节码文件的文件结构。接下来,我们进一步学习字节码的相关指令。
三分恶
2021/05/18
9000
【JVM进阶之路】十二:字节码指令
JVM学习第三天(JVM的执行子系统)之字节码指令
早上看了Class类文件结构,晚上继续来看字节码指令,毕竟谁也不是一步登天的(说白了还是穷);
彼岸舞
2020/09/30
5700
[三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符
计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。
noteless
2018/09/11
9.2K0
[三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符
深入浅出JVM(九、十)之字节码指令
本篇文章主要围绕字节码的指令,深入浅出的解析各种类型字节码指令,如:加载存储、算术、类型转换、对象创建与访问、方法调用与返回、控制转义、异常处理、同步等
菜菜的后端私房菜
2024/10/14
3190
jvm之类文件详解(四)
Class 文件是一组以 8 位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何 分隔符,这使得整个 Class 文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。 当遇到需要占用 8 位字节以上空间的数据项时,则会按照高位在前(Big-Endian)的方式分割成若干个 8 位字节进行存储。 Class 文件只有两种数据类型:无符号数和表 链接:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
周杰伦本人
2022/10/25
2160
jvm之类文件详解(四)
什么是字节码指令?[通俗易懂]
字节码指令简介: Java虚拟机的指令由一个字节长度的、代表着某种特定含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。 由于Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数的指令都不包含操作数,只有一个操作码。由于限制了Java虚拟机操作码的长度为一个字节,所以指令集的操作码总数不可能超过256条。
全栈程序员站长
2022/11/10
5860
Java 字节码指令,让我发了疯疯疯!
听我说,听我说,学 Java 准没错,毕竟岗位多薪资高!但涌进来的人越多,就意味着越来越卷,要想不被卷到,就必须得疯狂的学习,学什么呢?Java 字节码指令就是一块硬骨头。
沉默王二
2021/04/23
4960
Java 字节码指令,让我发了疯疯疯!
原 JVM基础命令
介绍java虚拟机的指令功能,至少能阅读java代码生成的字节码指令含义 一、概述 Java虚拟机采用基于栈的架构,其指令由操作码和操作数组成。 操作码:一个字节长度(0~255),意味着指令集的操作码个数不能操作256条。 操作数:一条指令可以有零或者多个操作数,且操作数可以是1个或者多个字节。编译后的代码没有采用操作数长度对齐方式,比如16位无符号整数需使用两个字节储存(假设为byte1和byte2),那么真实值是 (byte1 << 8) | byte2。 放弃操作数对齐操作数对齐方案: 优势:
石奈子
2018/06/13
8260
字节码也能做有趣的事
0.写在前面 为什么会写这篇文章呢?主要是之前调研过日志脱敏相关的一些,具体可以参考LOG4j脱敏插件如何编写 里面描述了日志脱敏插件编写方法: 直接在toString中修改代码,这种方法很麻烦,效率
用户5397975
2019/10/14
5620
字节码也能做有趣的事
JVM指令的速记
在学习的JVM的时候,最重要的是认识JVM的指令,JVM指令很多,为了方便记忆,可以根据前缀和功能进行分类:
付威
2020/05/06
1.1K0
Javap -c 字节码解析
栈和局部变量操作 将常量压入栈的指令 aconst_null         将null对象引用压入栈 iconst_m1         将int类型常量-1压入栈 iconst_0         将int类型常量0压入栈 iconst_1         将int类型常量1压入栈 iconst_2         将int类型常量2压入栈 iconst_3         将int类型常量3压入栈 iconst_4         将int类型常量4压入栈 iconst_5         将int类
房上的猫
2018/05/17
7440
JVM指令集及各指令的详细使用说明
一、JVM指令助记符 1)操作数栈 变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_ 操作数栈到变量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_ 常数到操作数栈:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,
汤高
2018/03/28
2.3K0
JVM的类文件结构,深入理解JVM必须趟过去的坎
读者阅读本章时,大概会不可避免地感到 比较枯燥,但这部分内容又是Java虚拟机的重要基础之一,是了解虚拟机的必经之路,如果想比较深 入地学习虚拟机相关知识,这部分是无法回避的。
燃192
2023/02/28
2630
JVM的类文件结构,深入理解JVM必须趟过去的坎
java黑科技-操作码
我们都知在Java中我们的类会被编译成字节码然后放到虚拟机中去执行,字节码里面的内容其实我们也是可以去“阅读”的,方法就是通过 jdk自带的工具翻译成操作码。在操作码中我们能看到一些我们平时看不到的关于java的秘密。
六个核弹
2020/09/22
5440
java字节码
  我们都知道Java字节码是JVM所使用的指令集。java字节码可以分为如下几类:
良辰美景TT
2018/09/11
1.7K0
java字节码
深入理解 JVM 之——字节码指令与执行引擎
对于 C 语言从程序到运行需要经过编译的过程,只有经历了编译后,我们所编写的代码才能够翻译为机器可以直接运行的二进制代码,并且在不同的操作系统下,我们的代码都需要进行一次编译之后才能运行。
浪漫主义狗
2023/09/07
5780
深入理解 JVM 之——字节码指令与执行引擎
记一次 JVM 源码分析(4.解释器与方法执行)
miniJVM 作为一个 mini 的 Java VM,实现了 Switch 解释器,并不支持主流 JVM 的 JIT 或者更为复杂的 AOT。但这样对于我们了解字节码的执行已经足够了。
JavaEdge
2020/05/27
1.5K0
记一次 JVM 源码分析(4.解释器与方法执行)
JVM简介—3.JVM的执行子系统
字节码是各种不同平台虚拟机与所有平台都能统一使用的程序存储格式,所以字节码(ByteCode)是构成平台无关性的基石,是语言无关性的基础。
东阳马生架构
2025/03/11
1260
JVM性能优化系列-(3) 虚拟机执行子系统
Java刚诞生的宣传口号:一次编写,到处运行(Write Once, Run Anywhere),其中字节码是构成平台无关的基石,也是语言无关性的基础。
码老思
2023/10/19
2070
JVM性能优化系列-(3) 虚拟机执行子系统
JVM 常用指令速查手册,建议收藏!
昨天在群里闲聊技术,提到了反编译和指令码。对于反编译和 JVM 的几个指令我解释了它们的各自所包含的意义。有人就问我,我是如何记住的。其实我也没记住这些指令,只不过,我总结了一个 JVM 常用指令速查手册,今天分享给大家!
业余草
2020/02/14
1K0
相关推荐
【JVM进阶之路】十二:字节码指令
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验