最通俗易懂的i++和++i詳解

前言

轉載請說明出處,本文來自Android菜鳥:https://blog.csdn.net/android_cai_niao/article/details/106027313 QQ:2717521606

我相信很多朋友可能之前已經百度過i++和++i的相關文章了,也做過不少的練習,覺得自己已經深刻掌握了它們之間的原理了,真的是這樣的嗎?來試試計算一下我下面提供的幾道練習,你就會發現你又不會了!

示例代碼

請先自己心算一下答案,然後找個本子記下來,然後再跟我後面的答案對比,看你能做對幾道題,能做對兩題以上的我喊你大哥!!

示例1

int i = 0;
i = i++; 
System.out.println("i = " + i); 

示例2

int a = 2; 
int b = (3 * a++) + a;
System.out.println(b);

示例3

int a = 2; 
int b = a + (3 * a++);
System.out.println(b);

示例4

int i = 1;
int j = 1;
int k = i++ + ++i + ++j + j++; 
System.out.println(k);

示例5

int a = 0;
int b = 0;
a = a++;
b = a++;
System.out.println("a = " + a + ", b = " + b);

示例答案

示例1:0
示例2:9
示例3:8
示例4:8
示例5:a = 1, b = 0

i++ 和 ++i原理

i++ 即後加加,原理是:先自增,然後返回自增之前的值
++i 即前加加,原理是:先自增,然後返回自增後的值
重點:這是一般人所不知道的,記住:不論是前++還是後++,都有個共同點是先自增。
對於++i 就不說了,大多數人都懂,而對於 i++ 的原理,我用代碼模擬其原理,如下:

int temp = i;
i = i + 1;
return temp;  

這3句代碼就是上面所說的那樣:i++是先自增,然後才返回自增之前的值。

i++字節碼分析

有很多的人寫的文章上都是說i++是先返回i的值,然後再自增,這是錯誤,是先自增,然後再返回自增之前的值,你可能會問,這有區別嗎?答案:有的。只要這個沒理解對,則你在計算i++的相關問題時就有可能算錯。

有的人可能又會問了,我憑什麼相信你,你有什麼證據證明i++是先自增,然後再返回自增之前的值嗎?我還真去找過證據,我們把class的字節碼搞出來,分析一下就知道了,證明如下:

public class Test {
    void fun() {
        int i = 0;
        i = i++;
    }
}

如上,我們寫了一個超級簡單的Test類。在cmd中輸入這個命令(javap -c Test.class)以查看其生成的字節碼,截圖如下:
在這裏插入圖片描述
我們關注fun()方法這一段就可以了,如下:
在這裏插入圖片描述
這就是fun()函數對應的字節碼了,我們一行一行的來分析,首先我們要說兩個概念,一個是變量,一個是操作棧,fun()方法中有兩個變量,哎,不是隻有一個變量i嗎?怎麼會有兩個?要了解這個你需要去學習字節碼的相關知識,這裏我們不深究,我畫圖如下:
在這裏插入圖片描述
如上圖,變量有兩個,在位置0的變量是什麼我們不要管,系統自動分配的,你要知道的是位置1的變量其實就是我們定義的變量i就行了,接下來,我們來一行行分析fun()方法對應的字節碼:
iconst_0 i代表int類型,const代表常量,0就代表整數0,整句話的意思就是把int類型的常量0放入操作棧的棧頂中,圖解如下:
在這裏插入圖片描述
istore_1 i代表int類型,store代表存儲,1代表位置爲1的變量,整句話的意思就是把操作棧中棧頂的值拿走,保存到位置爲1的變量上,圖解如下:
在這裏插入圖片描述
iload_1 i代表int類型,load代表加載變量的值,1代表位置爲1的變量,整句話的意思就是把位置爲1的變量的值加載到操作棧的棧頂中,圖解如下:
在這裏插入圖片描述
iinc 1, 1 i代表int類型,inc(increment)代表增加,這裏還有兩個1,前面的1代表對位置爲1的變量,第2個1代表增加1,因爲有i += 3這種自增操作,這種情況的話第個數字會是3,即自增3。“iinc 1, 1” 整句話的意思就是把位置爲1的變量的值增加1,圖解如下:
在這裏插入圖片描述
注:自增操作不會改變操作棧中的值,所以變量i的值自增後變成了1,而操作棧中的值還是0。

istore_1 i代表int類型,store代表存儲,1代表位置1的變量,整句話的意思就是:把棧頂中的值拿走,保存到位置爲1的變量中,圖解如下:
在這裏插入圖片描述
所以,這幾行字節碼合起來看,i++不就是先自增,然後才返回自增之前的值嘛!!所以大家千萬別搞錯順序了。 用代碼理解的話,就相當於下面的代碼:

int temp = i;
i = i + 1;
return temp;  

表達式原則

表達式有一個原則:一個變量也是表達式,多個表達式的加減法運算都是從左到右進行的

來看一下 if 語句的其中一種結構定義:

if (條件表達式) 語句;

用這個結構寫個代碼,如下:

boolean b = true;
int i = 0;
if(b) i++;

按照上面 if 語句的結構定義,if括號中是一個表達式,但是上面代碼寫了一個變量b進去,這是一個變量啊,怎麼也能當成一個表達式麼?沒錯,一個變量也是表達式。

記住這個重點:一個變量也是表達式,多個表達式的加減法運算都是從左到右進行的

講到這裏,估計有人會對這個運算順序和乘法這些搞混了,示例如下:

int a = 0;
int b = a + a * 2;

如上代碼,按着我的說法,一個變量也是一個表達式,“b = a + a * 2”這裏a出現了兩次,就是有兩個a表達式,從左到右算的話先算a + a,這肯定不對啊,這不是我的意思哈,乘除法的優先級還是不能亂的,那應該先算a * 2嗎?也不對,應該是這樣的:因爲有乘法,所以a * 2優先組成表達式,而不是a + a組成表達式,也就是說總體上可以分爲兩個表達式:“a” 表達式 和 “a * 2” 表達式,這兩個表達式相加肯定從左到右計算嘛,先算完a表達式的結果,再算a * 2表達式的結果。你可能會想先算a和先算a * 2有區別嗎?答案是:有的,看完下面 的“示例3詳解” 你就清楚了。

示例答案詳解

示例1詳解

int i = 0;
i = i++;  
System.out.println("i = " + i);  // 結果:0

先看i++,根據原理“先自增,然後返回自增之前的值”,i 自增後,i = 1,但是接着返回自增之前的值0,此時表達式變成 i = 0,0沒有賦值給 i 時 i 的值是1,但是當把0賦值給 i 時,i 的值就又變成0了。因此 i = i++ 這句代碼是做無用功,因爲 i 的值最終還是和原來一樣。

示例2詳解

int a = 2; 
int b = (3 * a++) + a;
System.out.println(b);   // 結果:9

int b = (3 * a++) + a;a++後,a = 3,並返回自增之前的值2,所以此時表達式爲:

int b = (3 * 2) + a;此時a的值已經是3了,表達式又變爲:

int b = (3 * 2) + 3; 所以b = 9

示例3詳解

int a = 2; 
int b = a + (3 * a++);
System.out.println(b); // 結果:8

這題和示例2幾乎一樣啊,只是換了一下順序而已,爲什麼結果就不一樣了呢?這就需要用到“表達式原則 了”:一個變量也是表達式,多個表達式的加減法運算都是從左到右進行的

int b = a + (3 * a++);按一般人的想法是先算 3 * a++,a 先自增 a=3,然後返回自增之前的值2,所以此時表達式變爲:

int b = a + (3 * 2); 此時a的值爲3了,表達式又變爲:

int b = 3 + (3 * 2);結果 b = 9

我們說一個變量也是表達式,多個表達式的加減法運算都是從左到右進行的,這個理論你可能不能深刻體會,但是如果我把代碼稍微改一下你就能理解了,如下:

int b = (a * 1) + (3 * a++) 這個代碼和 int b = a + (3 * a++) 是一樣的,沒有區別,但是看(a *1)你就很容易的知道要先算a * 1這個表達式,表達式的結果爲2。

所以,雖然 int b = a + (3 * a++) 中前面的a只是一個變量,但他也是一個表達式,a這個表達式和(3 * a++)這個表達式進行相加,多個表達式的運算都是從左到右進行的,所以先算a這個表達式,a表達式計算結果爲2,所以表達式變成:

int b = 2 + (3 * a++) 然後是a自增並返回自增之前的值2,所以表達式又變爲:

int b = 2 + (3 * 2);所以結果爲8。此時a的值爲3

示例4詳解

int i = 1;
int j = 1;
int k = i++ + ++i + ++j + j++;  
System.out.println(k);  // 結果:8

有了前面3條示例的詳解,相信這一條大家就能自己解答了,可以先自己解答一下,看結果是不是8,不是的話,再來看我下面的講解:

表達式原則說多個表達式的加減法運算都是從左到右進行的,這裏的表達式有:i++、++i、++j、j++,都是加法,那我們就從左到右計算這4個表達式就OK了,如下:

1、先算i++,i++之後i的值爲2,並返回++之前的值1,所以整個表達式可以變爲:

1 + ++i + ++j + j++; // 此時的i值爲2

2、再計算++i,++i之後i的值爲3,並返回3,所以整個表達式可以變爲:

1 + 3 + ++j + j++; // 此時i的值爲3

3、再計算++j,++j之後j的值爲2,並返回2,所以整個表達式可以變爲:

1 + 3 + 2 + j++; // 此時j的值爲2

4、再計算j++,j++之後 j的值爲3,並返回2,所以整個表達式可以變爲:

1 + 3 + 2 +2; // 結果爲8,此時j的值爲3

示例5詳解

int a = 0;
int b = 0;
a = a++;
b = a++;
System.out.println("a = " + a + ", b = " + b); // a = 1, b = 0

到了第5題,好像已經沒有難度了,大家應該都能解出來了,但是爲了文章的完整性,我還是分解一下,大家應該自己先算一次,算不對再來看我的分解:

a = a++; a++之後a的值爲1,並返回0,此時a的值爲1,但是接着0又賦值給了a,所以a的值變爲了0
b = a++; 上一行代碼執行之後 a的值還是0,再到這裏的a++,a的值就變成了1,返回0,0賦值給b,所以b爲0,而a還是1哦!!

總結

  • i++ 即後加加,原理是:先自增,然後返回自增之前的值
  • ++i 即前加加,原理是:先自增,然後返回自增後的值
  • 一個變量也是表達式,多個表達式的加減法運算都是從左到右進行的
  • 真實開發中,我們不會寫這些複雜的i++代碼,但是爲什麼還要掌握這些細節呢?答:筆試,萬一筆試的時候遇到這樣的題目呢?回答對了就可以加分了,因爲這種題很多人是答不出來的,而你回答出來了,那可是很加分的哦!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章