i++和 ++i的区别

前言

我们平常工作中对某个数进行累加的时候,一般都是用i++,但是我看HashMap和其他一些jdk里面的代码,用到自增基本上用的都是
++i,这两个有啥区别呢?我们都知道一个是i++先赋值再自增, 另一个是先自增再赋值。我们只知其然,不知其所以然。
今天我尝试给大家解释一下,希望我能表达清楚吧。

测试代码

首先列出我们的测试代码,你可以想一下这个i会打印几。

i++

    public static void main(String[] args) {
        int i = 8;
        i = i++;
        System.out.println(i);
    }

++i

    public static void main(String[] args) {
        int i = 8;
        i = i++;
        System.out.println(i);
    }

我们通过测试可以知道 第一个main方法输出的是8,第二个输出是9,第二个我相信大家知道的不知道的都知道会输出9
至于第一个为啥会输出8,肯定有点懵。先要了解一点,方法执行都是以一个栈帧的形式放在虚拟机栈里面,虚拟机栈里面存放的内容有,局部变量表,操作数栈,动态链接,以及方法的出口。执行其实都是执行一条条的指令出栈和入栈。下面我们通过工具来看main方法的指令集,这里我们需要借助一个idea的插件jclasslib Bytecode viewer

Jclasslib插件

安装

在idea的plugins里面搜索jclasslib Bytecode viewer,然后点击安装
在这里插入图片描述

  • 使用
    鼠标光标放要查看二进制码的类名上,然后点击view,下拉框下面会有一个新的选项

在这里插入图片描述

我们就可以看到这个类的二进制码文件啦,我们找到main方法这一块,我们可以看到这个方法里面所有的指令我们把这些指令都列出来,一个个来解释他们的意思

这是i++的main方法指令集
在这里插入图片描述

在解释之前我们还需要先看下局部变量表的内容

在这里插入图片描述

具体指令意思可以查看https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.istore_n的官网

  • bipush 8 :这个指令实际上是bipush代表的是我们平常说的压栈,把8压到栈里面
  • istore_1 : 使用的指令istore_n 它从操作数堆栈中弹出,并且将局部变量中下标为1的值(从上面的局部变量表中可以知道这个值是我们的i)设置为value。
  • iload_1 :iload_n 将局部变量表n位置的值进行压栈
  • iinc 1 by 1 : iinc局部变量表1位置的值增加1(这一步是在局部变量表中执行,不会压栈)
  • getstatic #2 <java/lang/System.out>:getstatic这个获取系统的一个静态变量
  • invokevirtual #3 <java/io/PrintStream.println>:invokevirtual执行一个多态的方法
  • 15 return :返回

用到的指令都解释了一下,现在我们统一来解释一下i++的指令执行流程

 0 bipush 8
 2 istore_1
 3 iload_1
 4 iinc 1 by 1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return

1.8压到栈中
2.8从栈中弹出来,赋值给i,这个时候i=8
3.把i = 8 又压到栈中
4.i在局部变量表中自增,此时局部变量表中的为9,这个过程不会压栈所以此时栈中还是8
5.8弹出来赋值给i所以就从9变为了8

我们再来看下++i的操作指令

在这里插入图片描述

 0 bipush 8
 2 istore_1
 3 iinc 1 by 1
 6 iload_1
 7 istore_1
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #3 <java/io/PrintStream.println>
15 return

1.8压到栈中
2.8从栈中弹出来,赋值给i,这个时候i=8
3.i自增为9,此时把9压到栈中
4.再把9出栈,赋值给i 所以i = 9

总结

因为i++和++i的指令集中,一个是先压栈,再执行i++的指令,而++操作不会压栈,所以栈中的i还是之前存进去的8,而++i是先执行自增指令,再去压栈,再从栈中弹出赋值给i。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章