一看就懂的i++和++i示例代碼詳解
一看就懂的i++和++i詳解
前言
我相信很多朋友可能之前已經(jīng)百度過(guò)i++和++i的相關(guān)文章了,也做過(guò)不少的練習(xí),覺(jué)得自己已經(jīng)深刻掌握了它們之間的原理了,真的是這樣的嗎?來(lái)試試計(jì)算一下我下面提供的幾道練習(xí),你就會(huì)發(fā)現(xiàn)你又不會(huì)了!
示例代碼
請(qǐng)先自己心算一下答案,然后找個(gè)本子記下來(lái),然后再跟我后面的答案對(duì)比,看你能做對(duì)幾道題,能做對(duì)兩題以上的我喊你大哥?。?/p>
示例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 即前加加,原理是:先自增,然后返回自增之后的值
重點(diǎn):這是一般人所不知道的,記?。翰徽撌乔?+還是后++,都有個(gè)共同點(diǎn)是先自增。
對(duì)于++i 就不說(shuō)了,大多數(shù)人都懂,而對(duì)于 i++ 的原理,我用代碼模擬其原理,如下:
int temp = i; i = i + 1; return temp; 123
這3句代碼就是上面所說(shuō)的那樣:i++是先自增,然后才返回自增之前的值。
i++字節(jié)碼分析
有很多的人寫(xiě)的文章上都是說(shuō)i++是先返回i的值,然后再自增,這是錯(cuò)誤,是先自增,然后再返回自增之前的值,你可能會(huì)問(wèn),這有區(qū)別嗎?答案:有的。只要這個(gè)沒(méi)理解對(duì),則你在計(jì)算i++的相關(guān)問(wèn)題時(shí)就有可能算錯(cuò)。
有的人可能又會(huì)問(wèn)了,我憑什么相信你,你有什么證據(jù)證明i++是先自增,然后再返回自增之前的值嗎?我還真去找過(guò)證據(jù),我們把class的字節(jié)碼搞出來(lái),分析一下就知道了,證明如下:
public class Test {
void fun() {
int i = 0;
i = i++;
}
}如上,我們寫(xiě)了一個(gè)超級(jí)簡(jiǎn)單的Test類(lèi)。在cmd中輸入這個(gè)命令(javap -c Test.class)以查看其生成的字節(jié)碼,截圖如下:

我們關(guān)注fun()方法這一段就可以了,如下:

這就是fun()函數(shù)對(duì)應(yīng)的字節(jié)碼了,我們一行一行的來(lái)分析,首先我們要說(shuō)兩個(gè)概念,一個(gè)是變量,一個(gè)是操作棧,fun()方法中有兩個(gè)變量,哎,不是只有一個(gè)變量i嗎?怎么會(huì)有兩個(gè)?要了解這個(gè)你需要去學(xué)習(xí)字節(jié)碼的相關(guān)知識(shí),這里我們不深究,我畫(huà)圖如下:

如上圖,變量有兩個(gè),在位置0的變量是什么我們不要管,系統(tǒng)自動(dòng)分配的,你要知道的是位置1的變量其實(shí)就是我們定義的變量i就行了,接下來(lái),我們來(lái)一行行分析fun()方法對(duì)應(yīng)的字節(jié)碼:
“ iconst_0 ” i代表int類(lèi)型,const代表常量,0就代表整數(shù)0,整句話的意思就是把int類(lèi)型的常量0放入操作棧的棧頂中,圖解如下:

“ istore_1 ” i代表int類(lèi)型,store代表存儲(chǔ),1代表位置為1的變量,整句話的意思就是把操作棧中棧頂?shù)闹的米?,保存到位置?的變量上,圖解如下:

“ iload_1 ” i代表int類(lèi)型,load代表加載變量的值,1代表位置為1的變量,整句話的意思就是把位置為1的變量的值加載到操作棧的棧頂中,圖解如下:

“ iinc 1, 1 ” i代表int類(lèi)型,inc(increment)代表增加,這里還有兩個(gè)1,前面的1代表對(duì)位置為1的變量,第2個(gè)1代表增加1,因?yàn)橛衖 += 3這種自增操作,這種情況的話第2個(gè)數(shù)字會(huì)是3,即自增3(iinc 1, 3)。“iinc 1, 1” 整句話的意思就是把位置為1的變量的值增加1,圖解如下:

注:自增操作不會(huì)改變操作棧中的值,所以變量i的值自增后變成了1,而操作棧中的值還是0。
“ istore_1 ” i代表int類(lèi)型,store代表存儲(chǔ),1代表位置1的變量,整句話的意思就是:把棧頂中的值拿走,保存到位置為1的變量中,圖解如下:

所以,這幾行字節(jié)碼合起來(lái)看,i++不就是先自增,然后才返回自增之前的值嘛!!所以大家千萬(wàn)別搞錯(cuò)順序了。 用代碼理解的話,就相當(dāng)于下面的代碼:
int temp = i; i = i + 1; return temp;
最后再把++i的字節(jié)碼圖也貼一下,大家可以根據(jù)我上面講解的知識(shí)分析一下,就會(huì)知道++i和i++的區(qū)別了:
void fun() {
int i = 0;
i = ++i;
}
表達(dá)式原則
表達(dá)式有一個(gè)原則:一個(gè)變量也是表達(dá)式,多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的
來(lái)看一下 if 語(yǔ)句的其中一種結(jié)構(gòu)定義:
if (條件表達(dá)式) 語(yǔ)句;
用這個(gè)結(jié)構(gòu)寫(xiě)個(gè)代碼,如下:
boolean b = true; int i = 0; if(b) i++;
按照上面 if 語(yǔ)句的結(jié)構(gòu)定義,if括號(hào)中是一個(gè)表達(dá)式,但是上面代碼寫(xiě)了一個(gè)變量b進(jìn)去,這是一個(gè)變量啊,怎么也能當(dāng)成一個(gè)表達(dá)式么?沒(méi)錯(cuò),一個(gè)變量也是表達(dá)式。
記住這個(gè)重點(diǎn):一個(gè)變量也是表達(dá)式,多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的
講到這里,估計(jì)有人會(huì)對(duì)這個(gè)運(yùn)算順序和乘法這些搞混了,示例如下:
int a = 0; int b = a + a * 2;
如上代碼,按著我的說(shuō)法,一個(gè)變量也是一個(gè)表達(dá)式,“b = a + a * 2”這里a出現(xiàn)了兩次,就是有兩個(gè)a表達(dá)式,從左到右算的話先算a + a,這肯定不對(duì)啊,這不是我的意思哈,乘除法的優(yōu)先級(jí)還是不能亂的,那應(yīng)該先算a * 2嗎?也不對(duì),應(yīng)該是這樣的:因?yàn)橛谐朔?,所以a * 2優(yōu)先組成表達(dá)式,而不是a + a組成表達(dá)式,也就是說(shuō)總體上可以分為兩個(gè)表達(dá)式:“a” 表達(dá)式 和 “a * 2” 表達(dá)式,這兩個(gè)表達(dá)式相加肯定從左到右計(jì)算嘛,先算完a表達(dá)式的結(jié)果,再算a * 2表達(dá)式的結(jié)果。你可能會(huì)想先算a和先算a * 2有區(qū)別嗎?答案是:有的,看完下面 的“示例3詳解” 你就清楚了。
示例答案詳解
示例1詳解
int i = 0;
i = i++;
System.out.println("i = " + i); // 結(jié)果:0先看i++,根據(jù)原理“先自增,然后返回自增之前的值”,i 自增后,i = 1,但是接著返回自增之前的值0,此時(shí)表達(dá)式變成 i = 0,0沒(méi)有賦值給 i 時(shí) i 的值是1,但是當(dāng)把0賦值給 i 時(shí),i 的值就又變成0了。因此 i = i++ 這句代碼是做無(wú)用功,因?yàn)?i 的值最終還是和原來(lái)一樣。
示例2詳解
int a = 2; int b = (3 * a++) + a; System.out.println(b); // 結(jié)果:9
int b = (3 * a++) + a;a++后,a = 3,并返回自增之前的值2,所以此時(shí)表達(dá)式為:
int b = (3 * 2) + a;此時(shí)a的值已經(jīng)是3了,表達(dá)式又變?yōu)椋?/p>
int b = (3 * 2) + 3; 所以b = 9
示例3詳解
int a = 2; int b = a + (3 * a++); System.out.println(b); // 結(jié)果:8
這題和示例2幾乎一樣啊,只是換了一下順序而已,為什么結(jié)果就不一樣了呢?這就需要用到“表達(dá)式原則 了”:一個(gè)變量也是表達(dá)式,多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的
int b = a + (3 * a++);按一般人的想法是先算 3 * a++,a 先自增 a=3,然后返回自增之前的值2,所以此時(shí)表達(dá)式變?yōu)椋?/p>
int b = a + (3 * 2); 此時(shí)a的值為3了,表達(dá)式又變?yōu)椋?/p>
int b = 3 + (3 * 2);結(jié)果 b = 9
我們說(shuō)一個(gè)變量也是表達(dá)式,多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的,這個(gè)理論你可能不能深刻體會(huì),但是如果我把代碼稍微改一下你就能理解了,如下:
int b = (a * 1) + (3 * a++) 這個(gè)代碼和 int b = a + (3 * a++) 是一樣的,沒(méi)有區(qū)別,但是看(a *1)你就很容易的知道要先算a * 1這個(gè)表達(dá)式,表達(dá)式的結(jié)果為2。
所以,雖然 int b = a + (3 * a++) 中前面的a只是一個(gè)變量,但他也是一個(gè)表達(dá)式,a這個(gè)表達(dá)式和(3 * a++)這個(gè)表達(dá)式進(jìn)行相加,多個(gè)表達(dá)式的運(yùn)算都是從左到右進(jìn)行的,所以先算a這個(gè)表達(dá)式,a表達(dá)式計(jì)算結(jié)果為2,所以表達(dá)式變成:
int b = 2 + (3 * a++) 然后是a自增并返回自增之前的值2,所以表達(dá)式又變?yōu)椋?/p>
int b = 2 + (3 * 2);所以結(jié)果為8。此時(shí)a的值為3
示例4詳解
int i = 1; int j = 1; int k = i++ + ++i + ++j + j++; System.out.println(k); // 結(jié)果:8
有了前面3條示例的詳解,相信這一條大家就能自己解答了,可以先自己解答一下,看結(jié)果是不是8,不是的話,再來(lái)看我下面的講解:
表達(dá)式原則說(shuō)多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的,這里的表達(dá)式有:i++、++i、++j、j++,都是加法,那我們就從左到右計(jì)算這4個(gè)表達(dá)式就OK了,如下:
1、先算i++,i++之后i的值為2,并返回++之前的值1,所以整個(gè)表達(dá)式可以變?yōu)椋?/p>
1 + ++i + ++j + j++; // 此時(shí)的i值為2
2、再計(jì)算++i,++i之后i的值為3,并返回3,所以整個(gè)表達(dá)式可以變?yōu)椋?/p>
1 + 3 + ++j + j++; // 此時(shí)i的值為3
3、再計(jì)算++j,++j之后j的值為2,并返回2,所以整個(gè)表達(dá)式可以變?yōu)椋?/p>
1 + 3 + 2 + j++; // 此時(shí)j的值為2
4、再計(jì)算j++,j++之后 j的值為3,并返回2,所以整個(gè)表達(dá)式可以變?yōu)椋?/p>
1 + 3 + 2 +2; // 結(jié)果為8,此時(shí)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題,好像已經(jīng)沒(méi)有難度了,大家應(yīng)該都能解出來(lái)了,但是為了文章的完整性,我還是分解一下,大家應(yīng)該自己先算一次,算不對(duì)再來(lái)看我的分解:
a = a++; a++之后a的值為1,并返回0,所以a的值由1又變回了0
b = a++; a++之后a的值為1,并返回0,0賦值給b,所以b為0,而a還是1哦!!
總結(jié)
- i++ 即后加加,原理是:先自增,然后返回自增之前的值
- ++i 即前加加,原理是:先自增,然后返回自增之后的值
- 一個(gè)變量也是表達(dá)式,多個(gè)表達(dá)式的加減法運(yùn)算都是從左到右進(jìn)行的
- 真實(shí)開(kāi)發(fā)中,我們不會(huì)寫(xiě)這些復(fù)雜的i++代碼,但是為什么還要掌握這些細(xì)節(jié)呢?答:筆試,萬(wàn)一筆試的時(shí)候遇到這樣的題目呢?回答對(duì)了就可以加分了,因?yàn)檫@種題很多人是答不出來(lái)的,而你回答出來(lái)了,那可是很加分的哦!
相關(guān)文章
JS 將偽數(shù)組轉(zhuǎn)換成數(shù)組的實(shí)現(xiàn)示例
這篇文章主要介紹了JS 將偽數(shù)組轉(zhuǎn)換成數(shù)組,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
js實(shí)現(xiàn)帶翻轉(zhuǎn)動(dòng)畫(huà)圖片時(shí)鐘
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)帶翻轉(zhuǎn)動(dòng)畫(huà)的圖片時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
checkbox設(shè)置復(fù)選框的只讀效果不讓用戶勾選
有時(shí)候是只想告知用戶這個(gè)地方是可以進(jìn)行勾選操作的而不想讓用戶在此處勾選(比如在信息展示頁(yè)面),這時(shí)候就需要將復(fù)選框設(shè)置成只讀的效果,具體實(shí)現(xiàn)方法如下2013-08-08
詳解JavaScript中的類(lèi)型判斷與類(lèi)型轉(zhuǎn)換
這篇文章主要給大家講解一下JavaScript中的類(lèi)型判斷與類(lèi)型轉(zhuǎn)換的基本概念和使用方法,對(duì)我們的學(xué)習(xí)JavaScript的類(lèi)型判斷與轉(zhuǎn)換有一定的幫助,需要的朋友可以參考下2023-07-07
Swiper如何實(shí)現(xiàn)兩行四列輪播圖效果實(shí)例
大家應(yīng)該都知道,Swiper是純javascript打造的滑動(dòng)特效插件,面向手機(jī)、平板電腦等移動(dòng)終端,下面這篇文章主要給大家介紹了關(guān)于Swiper如何實(shí)現(xiàn)兩行四列輪播圖效果的相關(guān)資料,需要的朋友可以參考下2022-10-10
微信小程序轉(zhuǎn)換uniapp的遷移步驟以及遇到的問(wèn)題總結(jié)
最近公司有個(gè)需求,第一次遇到,把原生的微信小程序代碼轉(zhuǎn)換為uni-app項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于微信小程序轉(zhuǎn)換uniapp的遷移步驟以及遇到問(wèn)題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
js實(shí)現(xiàn)隨機(jī)8位驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)隨機(jī)8位驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
JS設(shè)置時(shí)間無(wú)效問(wèn)題的解決辦法
在發(fā)送短信息驗(yàn)證碼的時(shí)候要用到j(luò)s設(shè)置時(shí)間倒序問(wèn)題,有時(shí)候會(huì)導(dǎo)致js失效問(wèn)題,怎么辦呢?今天小編給大家分享JS設(shè)置時(shí)間無(wú)效問(wèn)題的解決辦法,需要的朋友參考下吧2017-02-02
JavaScript網(wǎng)絡(luò)請(qǐng)求工具庫(kù)axios使用實(shí)例探索
這篇文章主要為大家介紹了JavaScript網(wǎng)絡(luò)請(qǐng)求工具庫(kù)axios使用實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
JS監(jiān)聽(tīng)組合按鍵思路及實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了JS監(jiān)聽(tīng)組合按鍵思路及實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

