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. Nacos 服务发现,注册及管理

    Nacos Nacos(官网: https://nacos.io) 发现,注册及管理. Nacos 支持发现,配置及管理几乎所有类型的服务: Kubernetes Service gRPC | Dub ...

  2. Csharp线程

    CSharpe线程 目录 CSharpe线程 C#如何操作线程 Thread 1. Thread如何开启一个线程呢? 2. Thread中常见的API 3. thread的扩展封装 threadpoo ...

  3. SSL新年欢乐赛暨BPM退役赛(不含FK)

    目录 前言 C 大水题 题目 分析 代码 D 简单数据结构题 题目 分析 代码 H 上次题 题目 分析 代码 J 白给题 题目 分析 代码 前言 A,B水题,E,I原题 实际赛时400分(乐多毁我青春 ...

  4. #Dijkstra#洛谷 4943 密室

    题目 分析 考虑答案只可能是分别到或者哈利一个人到两个房间, 那么在罗恩的时候先不建不可走的边,等到哈利走的时候再建边 代码 #include <cstdio> #include < ...

  5. 网站优化之robots.txt

    本文于2015年底完成,发布在个人博客网站上. 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来. 在查询favicon.ico相关的资料时,无间中看到了robots.tx ...

  6. Go 语言学习:了解 const 关键字及常量声明

    如果一个变量应该有一个固定的.不能改变的值,你可以使用const关键字. const关键字将变量声明为"常量",这意味着它是不可改变和只读的. 语法 const CONSTNAME ...

  7. mysql 重新整理——索引优化explain字段介绍一 [九]

    前言 在七种介绍了explain这东西,那么具体来看下它是如何来运行的吧. 正文 id 来看一条语句:EXPLAIN select * from departments,dept_emp,employ ...

  8. 笔记本电脑上的聊天机器人: 在英特尔 Meteor Lake 上运行 Phi-2

    对应于其强大的能力,大语言模型 (LLM) 需要强大的算力支撑,而个人计算机上很难满足这一需求.因此,我们别无选择,只能将它们部署至由本地或云端托管的性能强大的定制 AI 服务器上. 为何需要将 LL ...

  9. 【NOIP2013模拟联考8】匹配(match) 题解

    B 组都说看不懂--我也解释不清啊--只能写这么详细了 其实就是道板题 省流:f[i][s][j]表示字符串长度i,匹配情况s,ac自动机节点j Problem Description 给定k个字符串 ...

  10. 开箱即用!Linux 内核首个原生支持,让你的容器体验飞起来!| 龙蜥技术

    简介: 本文将从 Nydus 架构回顾.RAFS v6 镜像格式和 EROFS over Fscache 按需加载技术三个角度来分别介绍这一技术的演变历程. 文/阿里云内核存储团队,龙蜥社区高性能存储 ...