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。

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