对前后自增++i与i++的补充

一、前言

想写这篇博客,主要是最近在leetcode刷了些题,然后遇到数组中自增位置的选择,感觉挺有意思的,于是就分析下原理。

我前一篇介绍i++的文章链接:https://blog.csdn.net/weixin_44765605/article/details/110746423?spm=1001.2014.3001.5501



二、测试代码

  • 大家可以想一下下面的数组输出是什么。
  • 测试代码:
    public static void main(String[] args) {
        int length = 10;
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = i;
        }
        int index = 0;
        array[index++] = array[index] + 1;
        System.out.println(Arrays.toString(array));
        array[index] = array[index++] + array[index];
        System.out.println(Arrays.toString(array));
        array[index] = array[index] + array[++index] + array[index];
        System.out.println(Arrays.toString(array));
    }
  • 测试结果:
[2, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 3, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 3, 8, 3, 4, 5, 6, 7, 8, 9]



三、从字节码上解释

  • 字节码:
0 bipush 10
 2 istore_1
 3 iload_1
 4 newarray 10 (int)
 6 astore_2
 7 iconst_0
 8 istore_3
 9 iload_3
10 iload_1
11 if_icmpge 24 (+13)
14 aload_2
15 iload_3
16 iload_3
17 iastore
18 iinc 3 by 1
21 goto 9 (-12)
24 iconst_0
25 istore_3
26 aload_2
27 iload_3
28 iinc 3 by 1
31 aload_2
32 iload_3
33 iaload
34 iconst_1
35 iadd
36 iastore
37 getstatic #2 <java/lang/System.out>
40 aload_2
41 invokestatic #3 <java/util/Arrays.toString>
44 invokevirtual #4 <java/io/PrintStream.println>
47 aload_2
48 iload_3
49 aload_2
50 iload_3
51 iinc 3 by 1
54 iaload
55 aload_2
56 iload_3
57 iaload
58 iadd
59 iastore
60 getstatic #2 <java/lang/System.out>
63 aload_2
64 invokestatic #3 <java/util/Arrays.toString>
67 invokevirtual #4 <java/io/PrintStream.println>
70 aload_2
71 iload_3
72 aload_2
73 iload_3
74 iaload
75 aload_2
76 iinc 3 by 1
79 iload_3
80 iaload
81 iadd
82 aload_2
83 iload_3
84 iaload
85 iadd
86 iastore
87 getstatic #2 <java/lang/System.out>
90 aload_2
91 invokestatic #3 <java/util/Arrays.toString>
94 invokevirtual #4 <java/io/PrintStream.println>
97 return

  • 注意,下面的字节码解释都是根据官网来的:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5

  • 刚进入main方法的时候大概是这样的:
    在这里插入图片描述

  • 为什么局部变量表只有四个而不是三个呢?那是因为前面for循环的i后面不用了,于是就把index放那里了,这应该是jvm的优化。

  • 此时通过字节码中的0-8标号(以下直接用数字不会再加标号),新建了一个数组,同时也初始化了三个变量到局部变量表中。

    • 0-8中还有些操作是在操作数栈中完成的,这里因为不是重点就不画了。
    • 然后9-21步就是给数组中元素赋值的过程,这里也不画了。
  • 以下是第27步iconst_0开始前的场景:
    在这里插入图片描述

  • 对于array[index++]这一行代码,它肯定是先在前面执行的(赋值是最后做的),array[index++]对应的是26-28步,但是这里用了比较巧妙的方式去自增:

    • 第26步和27步,将数组地址和index入操作数栈:
      在这里插入图片描述
  • 第28步,重点来了,后自增的发生就在这一步,发生在数组地址和索引入操作数栈后,局部变量表的index加1了:

在这里插入图片描述

  • 然后31aload_2和32iload_3这两步,把局部变量表位置的值放入操作数栈中:

在这里插入图片描述

  • 由上图可以看出array[index++] = array[index] + 1;的第二个array[index],它的index其实已经是1了,所以array[index++] = array[index] + 1;这一行结束后,弹栈后的运算相当于:对0x0001的数组第0索引位置,赋值:0x0001数组第1索引位置的值+1的值,因此出现的就是数组索引0的位置的值是1+1=2的情况。

  • 对于操作数栈中的运算,通过第33步的iaload弹出前两个元素组合成一个数组索引的位置array[1],再根据这个位置获取array[1]的值并压到操作数栈中,再通过iconst_1将常数1压入操作数栈中,然后通过第35步iadd弹出栈顶两个元素的值进行相加得到的结果压入操作数栈中,再通过第36步iasotre将栈顶三个元素弹出,第二次弹出的索引和第三次弹出的数组地址组合成一个地址array[0],并将第一次弹出的value(前面计算好的并放在栈顶的值)赋值给那个数组的位置。(后面赋值操作类似,就不讲了,主要还是自增这方面)

  • 对于array[index] = array[index++] + array[index];也同理,第三个index因为用的是第二个index自增后的值,因此这一步就是array[1] = array[1] + array[2],原理同上,所以array[1]的值就是1+2=3;

  • 那么对于array[index] = array[index] + array[++index] + array[index];中间的前自增要怎么理解呢?

  • 我们直接找到第70步,第70步到第74步都和前面一样,压入数组地址和索引,第75步iaload是因为遇到+,因此要提前获取到值(就是要先算,这里大概是运算符的优先级影响的,但与主题无关)放入操作数栈中,此时虚拟机栈和堆中的简图是这样的:
    在这里插入图片描述

  • 重点来了,现在不是先将索引index先入栈,前自增是在索引index入栈前,先自增,前自增的位置还是局部变量表,第76步iinc 3 by 1,局部变量表位置3的值+1变为3:

在这里插入图片描述

  • 然后前自增结束,第77步iload_3才将局部变量表位置3的值3压入操作数栈中:

在这里插入图片描述

  • 图中的操作数栈,0:数组地址,1:数组索引index2;2:array[2]的值2;3:数组地址;4:数组索引index2。

  • 中间的步骤就不画了,都是差不多的;

  • 因此最后这一行可以看成:array[2] = array[2] + array[3] + array[3];;因此array[2]的值就是8。



三、我的用法

  • 在刷题的时候,对于如下情况:
array[index] = array[index] + array[index];
index++;

可以一行就写完,同时也知道index++的最适合位置在哪:

array[index] = array[index] + array[index++];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)长5.05%;越南2023年经济长5.05%;马来西亚2023年经济速为3.7%;泰国2023年经济长1.9%;新加坡2023年经济长1.1%;柬埔寨2023年经济速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值