1. 程式人生 > >對於i++和++i的深入理解

對於i++和++i的深入理解

在學完jvm的一些知識後,發現有些令人云山霧罩的問題,逐漸變得條理清晰。首先,在這裡保證,看完以下解釋,讓你徹底明白i++和++i的原理,而不是停留在先賦值後運算的淺層次的理解。因為涉及底層,有些東西可能晦澀難懂,但難能可貴。但柳岸花明又一村,相信你可以。加油。

一、相關知識

以下介紹的知識是理解的必備裝備,在打“boss”前最後還是撿一些武器。

虛擬機器棧:java虛擬機器執行時資料區的一部分,一個執行緒對應一個棧,棧控制著方法的呼叫。
棧幀:虛擬機器棧的棧元素,每次呼叫一個方法,就會建立與方法對應的棧幀,並將棧幀入棧。
舉個栗子:

public class Main {
    public static void main(String[] args) {
        int i = 1;
        int j = i++;
    }
}

在這裡插入圖片描述

棧幀結構

區域性變量表: 是一片邏輯連續的記憶體空間,可以理解為類似陣列的結構,具有像slot0、slot1這樣的索引。它是用來存放方法引數和方法內部定義的區域性變數。
是按引數和區域性變數在程式碼中出現的順序而依次對應slot0、slot1、
slot2的儲存位置,為了更直觀寫了slot0(args),實際只有索引slot0,沒有args。

知識拓展slot:slot是虛擬機器為區域性變量表分配記憶體所使用的最小單位。對於byte,char,float,int,shot,boolean,reference和returnAddress等長度不超過32位的資料型別,每個區域性變數佔1個Slot,而double與long這兩種64位的資料型別而需要2個Slot來存放

運算元棧: Java虛擬機器提供指令來讓運算元棧對一些資料進行入棧操作,比如可以把區域性變量表裡的資料、例項的欄位、常量值等資料入棧。

棧幀的大小在編譯時就確定,區域性變量表的大小、運算元棧的大小也是在編譯時就確定大小的。

二、底層執行過程

(1) 反編譯得到main方法對應的位元組碼指令

cmd(windows命令列):javap -v Main.class
在這裡插入圖片描述
(注:stack即運算元棧,locals即區域性變量表)

接下來我們依次執行八條指令,索引是從0開始的。

以下大多數情況i開頭的i代表int型別
0: iconst_1 將int型常量值1入運算元棧
在這裡插入圖片描述


1: istore_1   出棧(運算元棧),並把出棧的值儲存到區域性變量表索引為1(從_1得知索引為1)的位置


在這裡插入圖片描述

2:iload_1   將索引為1即slot1處的值拷貝一份入棧
在這裡插入圖片描述
3: iinc 1, 1   *將索引為slot1處的值 加1
iinc index, constvalue
index:由執行++運算的變數在區域性變量表的位置決定,本測試中為i++,而i對應的區域性變量表的位置為slot1,所以index=1.
contstvalue: 由於++運算為變數加1,所以constvalue恆為一.

在這裡插入圖片描述
6: istore_2   出棧,並把值儲存到索引值為2即slot2處
在這裡插入圖片描述

int i = 1 ;
int j = i++;

最終執行結果: i = 2; j=1;
7: return    方法執行完畢,對應棧幀出棧
在這裡插入圖片描述

那麼++i是如何進行的呢?

Main.java

public class Main {
    public static void main(String[] args) {
        int i = 1;
        int j = ++i;
    }
}

位元組碼指令
在這裡插入圖片描述

執行流程:
在這裡插入圖片描述

看到這裡,參不多已經可以下山了。沒有一點小激動嗎?別急,臨走前,在給你本“葵花寶典”!
《葵花寶典》–對比圖
在這裡插入圖片描述

寫在結尾:純手工製作,沒有複製貼上。您的贊是對我最大的鼓勵!