Java变量自增表达式 i = i++ 的底层逻辑(简述)


前言

很多老师告诉我们,i = i++ 的运算过程是 temp = i; i ++; i = temp; 所以i的值不变。但我总觉得这个temp的出现有些莫名其妙。所以在网上检索之后,把大佬们的解释做了一点总结和简化,权当拾人牙慧。

要搞懂 i = i++ 我们先要简单认识两个东西:局部变量表操作数栈

  • 操作数栈:一个临时的存储空间, 主要用于保存计算过程的变量和中间结果,
  • 局部变量表:也是一个临时的存储空间,它用于保存函数的参数以及局部变量。
  • 对于本文章而言,初学者可以把它看做两个桶:一个用来装i的值(局部变量表),另一个用来装中间过程中用到的数(操作数栈)

正文

了解了以上内容,就可以对i=i++进行理解了。不过在此之前,我们先看看单独的i++ 和 ++i的区别:

i++ 和 ++i

i++ 和 ++i,它们实际上是直接在局部变量表里修改变量的值,原地修改,不需要经过操作数栈。所以,作为语句单独使用时,没有区别。

public static void main(String[] args) {
int i = 0;
i++; // 在局部变量表直接自增
++i; // 在局部变量表直接自增,没有区别
}

那么当情况是 i = i++时; 为什么结果就是i的值不变呢?

i = i++

public static void main(String[] args) {
int i = 0;
i = i++; // i值不变
}

这就是操作数栈参与的结果,上面代码的执行过程,实际上是这样的:

  • 执行 int i = 0;

    • 把0这个常数放到操作数栈中
    • 从操作数栈顶取出常数0,然后存储到局部变量表的索引为1的位置(局部变量表[1]),这个位置就代表i的值(因为局部变量表里有args 和 i 两个元素,args的索引是0)。
  • 执行 i = i++;
    • 计算机首先看见右侧表达式中的i, 所以它把局部变量表[1]的值取出,压入操作数栈。
    • 计算机又看见了符号“++”,于是把局部变量表[1]进行自增
    • 然后计算机看见 “=” ,所以对等号左边的i进行赋值,重点来了
      • 这里赋的是哪个值呢? -- 操作数栈里的值,0。
      • 那么赋值到哪里呢? -- 局部变量表[1]。直接覆盖了自增的结果,也就是说,刚刚的自增操作,增了个寂寞。
    • 所以我们就知道了:由于刚刚是“先压栈,再自增”,所以栈里的值还是原始值,最后又覆盖回去了。
  • 同理,我们也就知道它和 i = ++i 的不同之处在哪里了
    • 计算机这次首先看见的是“++”符号,而不是i, 所以它这次先把局部变量表[1]进行自增
    • 然后计算机才看见了i,此时才把局部变量表[1]的值取出,压入操作数栈,因此,栈里的值也变成了1,最后覆盖回去就是1。

以上顺序的变化,实际上在JVM编译后的字节码文件中能够直观地看到,但是初学者对字节码很陌生,所以采用了以上的描述方式。字节码的区别其实更加直观,如下:

  • i = i++ 的执行顺序:
iconst_0  # 把int常量0压入操作数栈
istore_1 # 把操作数栈顶的值"0"存储到局部变量表[1]
iload_1 # 局部变量表[1]的值压入操作数栈顶,此时操作数栈顶为0
iinc 1 1 # 将局部变量表[1]的值,加上1, 所以此时i的值变成1
istore_1 # 将操作数栈顶的值存储到局部变量表[1], 用0覆盖了1.
  • i = ++i 的执行顺序:
iconst_0  # 同上
istore_1 # 同上
iinc 1 1 # 将局部变量表[1]的值,加上1, 此时i的值变成1
iload_1 # 局部变量表[1]的值压入操作数栈顶,此时操作数栈顶为1
istore_1 # 将操作数栈顶的值存储到局部变量表[1], 用1覆盖了1.

这个问题的进阶还有 k = i + ++i * i++ 参考文章:https://blog.csdn.net/See_Star/article/details/125206538


作者: 练块儿的程序员

出处:https://www.cnblogs.com/sunyujun16

本文版权归作者和博客园共有,欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文链接, 如有问题,可邮件sunyujun16@163.com咨询.

Java变量自增表达式 i = i++ 的底层逻辑(简述)的更多相关文章

  1. Java——变量自增(++)自减(--)

    //运算符在操作数之后,称为“后增量”.i变量自增,返回自增之前的值;//运算符在操作数之前,称为“前增量”.i变量自增,返回自增之后的值.//自减同理 public static void test ...

  2. Java变量自增和自减运算符的用法

    1.后加加(num++): 先输出运算结果再加加: public static void main(String[] args){ int num=10; int  p1=num++; System. ...

  3. JAVA 变量 数据类型 运算符 知识小结

    ---------------------------------------------------> JAVA 变量 数据类型 运算符 知识小结 <------------------ ...

  4. Lambda 表达式,Java中应用Lambda 表达式

    一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...

  5. Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】

    原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...

  6. java字符串应用之表达式解析器

    一.表达式的组成    1.数字    2.运算符:+ - / * ^ % =    3.圆括号    4.变量二.运算符优先级    由高到低分别为:+-(正负号).^.*/%.+-.=    优先 ...

  7. Java精选笔记_EL表达式

    EL表达式 初始EL EL是一种可以简化JSP页面的表达式,EL表达式的语法非常简单都是以"${"符号开始,以"}"符号结束的 EL表达式是一种简单的数据&qu ...

  8. Java变量声明和赋值

    Java的8种基础类型变量声明,在得到Java 11支持后会有新的语法糖 基础数据类型一共有8种 整数类型:byte.short.int和long 小数类型:float和double 字符类型:cha ...

  9. Java代码三级跳——表达式、语句和代码块

    Java代码三级跳—表达式.语句和代码块 表达式(expression):Java中最基本的一个运算.比如一个加法运算表达式.1+2是一个表达式,a+b也是. 语句(statement):类似于平时说 ...

  10. java基础知识-lambda表达式

    一.什么是lambda? 在Java中,我们可以将一个值赋值给一个Java变量. int aValue = 129; String aString = "hello world"; ...

随机推荐

  1. .Net Core AutoFac 使用方法讲解大全,具体详细使用知识总结

    AutoFac 具体使用知识总结 阅读前提示 AutoFac 只是众多IOC框架的其中一种, 比较主流的有Unity.autofac.spring.net.MEF.Injection.Asp.Net ...

  2. Bootstrap实战 - 评论列表

    一.介绍 社交媒体网站盛行,人们常常会使用评论表达自己的观点,评论功能已然成为网站的一部分. 二.知识点 2.1 媒体对象 官方解释:这是一个抽象的样式,用以构建不同类型的组件,这些组件都具有在文本内 ...

  3. OpenHarmony Meetup北京站招募令

    OpenHarmony Meetup城市巡回北京站火热来袭!!日期:2023年11月25日14:00地点:中国科学院软件园区五号楼B402与OpenHarmony技术大咖近距离互动,分享技术见解,结交 ...

  4. C 语言指针完全指南:创建、解除引用、指针与数组关系解析

    C 语言中的指针 创建指针 我们可以使用引用运算符 & 获取变量的内存地址: int myAge = 43; // 一个 int 变量 printf("%d", myAge ...

  5. Docker学习路线11:Docker命令行

    Docker CLI (命令行界面) 是一个强大的工具,可让您与 Docker 容器.映像.卷和网络进行交互和管理.它为用户提供了广泛的命令,用于在其开发和生产工作流中创建.运行和管理 Docker ...

  6. HDC技术分论坛:ArkCompiler(方舟编译器)原理解析

    作者:xianyuqiang 编译器首席架构师 ArkCompiler(方舟编译器)是组件化.可配置的多语言编译和运行平台,它既能支撑单一语言运行环境,也能支撑多种语言组合的运行环境.它目前主要支持的 ...

  7. 应用可靠性与性能不给力?HarmonyOS HiViewDFX了解一下

    原文链接:https://mp.weixin.qq.com/s/Y44jUEB3ttlijbMDPrBcNg,点击链接查看更多技术内容:   作为基础软件服务子系统的HarmonyOS HiViewD ...

  8. 服务器日志qsnctfwp

    使用 WireShark 打开日志文件 log.pcpng 获取恶意用户下载的文件 方法一:通过对 FTP-DATA 对象导出,可知下载了名为 flag 的文件,通过 save 可获取文件 方法二:通 ...

  9. 填报表中也可以添加 html 事件

    在实际的项目开发中,填报表的应用十分广泛. 多数情况下,填报表会作为整个项目的一部分配合需求灵活使用,但有时也会受大项目环境的影响,产生一些特别的要求.比如,通常报表单元格的数据类型大多是文本,有时却 ...

  10. sql 语句系列(月份的第一天和最后一天)[八百章之第二十章]

    前言 插播一个,从给定日期值里面提取年月日时分秒. 之所以写这个是因为使用频率太高. mysql: select DATE_FORMAT(CURRENT_TIMESTAMP,'%k') hr, DAT ...