你真的了解 i++, ++i 和 i+++++i 以及 i+++i++ 吗?

我想大部分都知道 i++ 和 ++i的区别,i++ 就是先拿i来使用,之后再自增加1,而++i则是先自增加1,在拿i来使用,例如对于下面这两个语句,我敢保证大部分人都会做:

答案分别为 1,2。对于这个答案我猜大多数人都能答出来。不过 i++ 和 ++i 这两个操作,在内部是如何实现的呢?

我们先来看另外一个问题:

这个比刚才那个难了点,答案分别是3,3。假如你对这个答案的由来了如指掌,那么你大不可必往下看,假如你不大理解或者想从底层的汇编指令的来了解这个操作,那么你可以看看我的解释。

首先我们先来看看 i++ 的题,主要是为了后面好解释点。

这两行代码的部分汇编指令如下,注意,我只列出了几个重点的汇编语句:

所以,此时打印的是1。

有些人可能没弄过汇编会有点懵逼,没事,我花个时间画个图来模拟(注:省略很多细节)。

刚开始时的局部变量表和操作数栈如图所示:

2、执行 ISTORE 1,栈顶元素出栈存到位置“1”

3、执行  ILOAD 1,把位置“1”的变量值存到栈顶

4、执行 IINC 1 1 ,直接把局部变量表中位置为“1”的变量加 1

5、执行 INVOKEVIRTUAL java/io/PrintStream.println (I)V  ,把栈顶的元素打印出来,此时栈顶的元素是 1.

所以虽然i已经等于2了,但此时栈顶的元素却是i之前的值 1 ,所以打印的是1。

这下关于 i ++ 的懂了吧?

 

那我们来看看 ++ i 与  i ++  的汇编指令有什么不同。

对应的部分重点汇编指令如下:

再画下图演示一下:

 

1、执行了ICONST_1 和ISTORE 1这两句过后的局部变量和栈的情况如下

2、执行 IINC 1 1。注意,执行这条指令,操作数栈不会发生变化。

3、执行 ILOAD 1,把位置“1”的变量值压入栈顶

4、执行 INVOKEVIRTUAL java/io/PrintStream.println (I)V  ,把栈顶的元素打印出来,此时栈顶的元素是 2

所以,对于 i++ 和 ++i的区别彻底懂了吧。

接下来我们来分析这个程序

这里先说一下,按照运算符号的优先顺序,i+++i++等价于 (i++) + (i++)。

对应的部分汇编指令如下:

如果上面的那两个 i++ 和 ++i你看懂了,那么上面那个汇编应该也差不多能看懂。我用图来逐条分析一下吧。

1、执行了 ICONST_1 和ISTORE 1之后的状态如下

2、执行 ILOAD 1

3、执行 IINC 1 1

4、执行  ILOAD 1

5、执行 IINC  1 1。

此时实际上 i 的值已经是 3 了,只是栈顶放的都是 i 的旧值。

6、执行 IADD ,把栈顶两个元素出栈相加后再把结果入栈

7、执行INVOKEVIRTUAL java/io/PrintStream.println (I)V,此时栈顶元素为3,所以打印的是3

8、执行  ILOAD 1,把局部变量表加载到栈顶

9、执行INVOKEVIRTUAL java/io/PrintStream.println (I)V,此时栈顶元素为3,所以打印的是3

完毕

现在知道了把,对于 i+++++i 的题也知道怎么做以及怎么回事了吧。

这篇文章重点让你理解 i++ 与 ++ i的实现机制,对于上面的汇编指令以及进栈入栈的过程为了更好着说明要解决的问题,所以隐藏了很多细节,而且也删除了部分代码。如有错误的地方,还请指教。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值