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. mybatis踩坑之integer类型是0的时候会被认为0!=''是假

    当你的参数类型是integer类型,并且传的是0的时候,在SQL里面做if判断的时候 <if test="auditStatus != null and auditStatus != ...

  2. #排列组合#CF1550D Excellent Arrays

    洛谷传送门 CF1550D 分析 对于excellent的 \(a\) 来说 \(|a_i-i|=x\) 的值是固定的,考虑枚举它 一半正一半负时函数值是最大的,当 \(n\) 为奇数时要分为两种情况 ...

  3. SQLite主键自增代码

    引用:https://blog.csdn.net/maowendi/article/details/81115401 insert into TubeRunInfo (UserName) values ...

  4. django admin后台自定义数据保存方式

    故事背景是这样的: 为了方便工作中数据的整理,需要开发一个 管理系统,用于记录一些事情. 该系统不需要精美的前端的页面,只需要使用django的admin后台管理就可以了. 我需要在添加数据的时候,把 ...

  5. Quanto: PyTorch 量化工具包

    量化技术通过用低精度数据类型 (如 8 位整型 (int8)) 来表示深度学习模型的权重和激活,以减少传统深度学习模型使用 32 位浮点 (float32) 表示权重和激活所带来的计算和内存开销. 减 ...

  6. 重新点亮linux 命令树————su和sudo[七]

    前言 简单整理一下su和sudo这两个命令. 正文 su 这个命令是用来切换用户的. 一般我们切换命令su,还是在原来的路径下面,但是如果想要直接回到切换用户的用户目录的话,可以使用su - user ...

  7. 第 9章 数据分析案例:Python 岗位行情

    第 9章 数据分析案例:Python 岗位行情 9.1 数据爬取 (1)打开某招聘网站首页 https://www.lagou.com,选择"全国站",在搜索栏输入 Python, ...

  8. MaxCompute 公共云多租户设计的技术要点详解及产品实现特色

    ​简介:公共云大数据平台在多租户的设计和实现方式上有所差异.本文主要介绍在公共云大数据平台的多租实现方案中需要考虑的问题和挑战,重点介绍了MaxCompute在计算和存储多租实现上的特点.期望通过这些 ...

  9. 阿里云实时数仓Hologres年度发布,解读数仓新趋势

    ​简介:阿里云实时数仓Hologres年度发布,解读数仓新趋势. 1月7日,阿里云实时数仓Hologres发布最新版本,在成本.可用性.在线高可用等多方面进行了能力升级,行存吞吐提升100%,列存吞吐 ...

  10. Quick BI:降低使用门槛,大东鞋业8000家门店的数据导航

    简介: 通过引入MaxCompute和Quick BI,大东解决了以往数据查询即刻导致数据库闪崩的状况,还搭建起完善的报表体系,稳定应对高频.高并发的数据分析. 大东鞋业一季大约有500款的新品.大区 ...