自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官又整新活,居然問(wèn)我 For 循環(huán)用 i++ 和 ++i 哪個(gè)效率高?

開(kāi)發(fā) 前端
聽(tīng)到這,我感覺(jué)這面試官確實(shí)有點(diǎn)不按套路出牌了,放著好好的八股文不問(wèn),凈整些幺蛾子的東西。在臨走的時(shí)候,小伙伴問(wèn)面試官這道題的答案是什么,面試官?zèng)]有明確告訴答案,只是說(shuō)讓從程序執(zhí)行的效率角度自己思考一下。

前幾天,一個(gè)小伙伴告訴我,他在面試的時(shí)候被面試官問(wèn)了這么一個(gè)問(wèn)題:

在for循環(huán)中,到底應(yīng)該用 i++ 還是 ++i ?

聽(tīng)到這,我感覺(jué)這面試官確實(shí)有點(diǎn)不按套路出牌了,放著好好的八股文不問(wèn),凈整些幺蛾子的東西。在臨走的時(shí)候,小伙伴問(wèn)面試官這道題的答案是什么,面試官?zèng)]有明確告訴答案,只是說(shuō)讓從程序執(zhí)行的效率角度自己思考一下。

好吧,既然這個(gè)問(wèn)題被拋了出來(lái),那我們就見(jiàn)招拆招,也給以后面試的小伙伴們排一下坑。

思路

前面提到,這個(gè)搞事情的面試官說(shuō)要從執(zhí)行效率的角度思考,那我們就拋開(kāi)語(yǔ)義上的區(qū)別,從運(yùn)行結(jié)果以外的效率來(lái)找找線索?;叵胍幌?,我們?cè)谝郧敖榻BCAS的文章中提到過(guò),后置自增i++和前置自增++i都不是原子操作,那么實(shí)際在執(zhí)行過(guò)程中是什么樣的呢?下面,我們從字節(jié)碼指令的角度,從底層進(jìn)行一波分析。

i++ 執(zhí)行過(guò)程

先寫(xiě)一段簡(jiǎn)單的代碼,核心功能就只有賦值和自增操作:

  1. public static void main(String[] args) { 
  2.     int i=3; 
  3.     int j=i++; 
  4.     System.out.println(j); 

下面用javap對(duì)字節(jié)碼文件進(jìn)行反編譯,看一下實(shí)際執(zhí)行的字節(jié)碼指令:

是不是有點(diǎn)難懂?沒(méi)關(guān)系,接下來(lái)我們用圖解的形式來(lái)直觀地看看具體執(zhí)行的過(guò)程,也幫大家解釋一下晦澀的字節(jié)碼指令是如何操作棧幀中的數(shù)據(jù)結(jié)構(gòu)的,為了簡(jiǎn)潔起見(jiàn),在圖中只列出棧幀中比較重要的操作數(shù)棧和局部變量表。

上面的代碼中除去打印語(yǔ)句,整體可以拆分成兩步,我們先看第一步 int i=3 是如何執(zhí)行的 。

上面兩條操作數(shù)棧和局部變量表相關(guān)的字節(jié)碼指令還是比較容易理解的,下面再看一下第二步int j=i++的執(zhí)行過(guò)程:

在上圖中需要注意的是,iinc能夠直接更新局部變量表中的變量值,它不需要把數(shù)值壓到操作數(shù)棧中就能夠直接進(jìn)行操作。在上面的過(guò)程中,拋去賦值等其他操作,i++實(shí)際執(zhí)行的字節(jié)碼指令是:

  1. 2: iload_1 
  2.  
  3. 3: iinc 1, 1 

如果把它翻譯成我們能看懂的java代碼,可以理解為:

  1. int temp=i; 
  2.  
  3. i=i+1; 

也就是說(shuō)在這個(gè)過(guò)程中,除了必須的自增操作以外,又引入了一個(gè)新的局部變量,接下來(lái)我們?cè)倏纯?+i的執(zhí)行過(guò)程。

++i 執(zhí)行過(guò)程

我們對(duì)上面的代碼做一點(diǎn)小小的改動(dòng),僅把i++換成++i,再來(lái)分析一下++i的執(zhí)行過(guò)程是怎樣的。

  1. public static void main(String[] args) { 
  2.  
  3. int i=3; 
  4.  
  5. int j=++i; 
  6.  
  7. System.out.println(j); 
  8.  

同樣,用javap反編譯字節(jié)碼文件:

int i=3對(duì)應(yīng)前兩行字節(jié)碼指令,執(zhí)行過(guò)程和前面i++例子中完全相同,可以忽略不計(jì),重點(diǎn)還是通過(guò)圖解的方式看一下int j=++i對(duì)應(yīng)的字節(jié)碼指令的執(zhí)行過(guò)程:

拋去賦值操作,++i實(shí)際執(zhí)行過(guò)程只有一行字節(jié)碼指令:

  1. 2: iinc 1, 1 

轉(zhuǎn)換成能理解的java代碼的話,++i實(shí)際執(zhí)行的就在局部變量中執(zhí)行的:

  1. i=i+1; 

這么看來(lái),在使用++i時(shí)確實(shí)比i++少了一步操作,少引入了一個(gè)局部變量,如果在運(yùn)算結(jié)果相同的場(chǎng)景下,使用++i的話的確效率會(huì)比i++高那么一點(diǎn)點(diǎn)。

那么回到開(kāi)頭的問(wèn)題,兩種自增方式應(yīng)用在for循環(huán)中執(zhí)行的時(shí)候,那種效率更高呢?剛才得出的結(jié)論仍然適用于for循環(huán)中嗎,別急,讓我們接著往下看。

for循環(huán)中的自增

下面準(zhǔn)備兩段包含了for循環(huán)的代碼,分別使用i++后置自增和++i前置自增:

  1. //i++ 后置自增 
  2. public class ForIpp { 
  3.     public static void main(String[] args) { 
  4.         for (int i = 0; i < 5; i++) { 
  5.             System.out.println(i); 
  6.         } 
  7.     } 
  8. //++i 前置自增 
  9. public class ForPpi { 
  10.     public static void main(String[] args) { 
  11.         for (int i = 0; i < 5; ++i) { 
  12.             System.out.println(i); 
  13.         } 
  14.     } 

老規(guī)矩,還是直接反編譯后的字節(jié)碼文件,然后對(duì)比一下指令的執(zhí)行過(guò)程:

到這里,有趣的現(xiàn)象出現(xiàn)了,兩段程序執(zhí)行的字節(jié)碼指令部分居然一模一樣。先不考慮為什么會(huì)有這種現(xiàn)象,我們還是通過(guò)圖解來(lái)看一下字節(jié)碼指令的執(zhí)行過(guò)程:

可以清晰的看到,在進(jìn)行自增時(shí),都是直接執(zhí)行的iinc,在之前并沒(méi)有執(zhí)行iload的過(guò)程,也就是說(shuō),兩段代碼執(zhí)行的都是++i。這一過(guò)程的驗(yàn)證其實(shí)還有更簡(jiǎn)單的方法,直接使用idea打開(kāi)字節(jié)碼文件,就可以看到最終for循環(huán)中使用的相同的前置自增方式。

那么,為什么會(huì)出現(xiàn)這種現(xiàn)象呢?歸根結(jié)底,還是java編譯器對(duì)于代碼的優(yōu)化,在兩種自增方式中,如果沒(méi)有賦值操作,那么都會(huì)被優(yōu)化成一種方式,就像下面的兩個(gè)方法的代碼:

  1. void ipp(){ 
  2.     int i=3; 
  3.     i++; 
  4. void ppi(){ 
  5.     int i=3; 
  6.     ++i; 

最終執(zhí)行時(shí)的字節(jié)碼指令都是:

  1. 0: iconst_3 
  2.  
  3. 1: istore_1 
  4.  
  5. 2: iinc 1, 1 
  6.  
  7. 5: return 

可以看到,在上面的這種特定情況下,代碼經(jīng)過(guò)編譯器的優(yōu)化,保持了語(yǔ)義不變,并通過(guò)轉(zhuǎn)換語(yǔ)法的形式提高了代碼的運(yùn)行效率。所以再回到我們開(kāi)頭的問(wèn)題,就可以得出結(jié)論,在for循環(huán)中,通過(guò)jvm進(jìn)行編譯優(yōu)化后,不論是i++還是++i,最終執(zhí)行的方式都是++i,因此執(zhí)行效率是相同的。

所以,以后再碰到這種半吊子的面試官,和你談for循環(huán)中i++和++i的效率問(wèn)題,自信點(diǎn),直接把答案甩在他的臉上,兩種方式效率一樣! 

本文代碼基于Java 1.8.0_261-b12 版本測(cè)試

 

責(zé)任編輯:武曉燕 來(lái)源: 碼農(nóng)參上
相關(guān)推薦

2022-03-31 16:47:30

mysqlcount面試官

2019-09-11 09:09:56

++ii++編程語(yǔ)言

2022-11-25 17:29:27

分布式事務(wù)

2021-12-02 08:19:06

MVCC面試數(shù)據(jù)庫(kù)

2024-04-08 10:35:59

JS代碼容量

2023-09-28 08:21:20

i++++i高并發(fā)

2021-05-20 08:54:16

Go面向對(duì)象

2020-04-16 08:22:11

HTTPS加解密協(xié)議

2010-08-23 15:06:52

發(fā)問(wèn)

2022-05-24 08:03:28

InnoDBMySQL數(shù)據(jù)

2020-10-26 07:07:50

線程安全框架

2021-08-02 09:31:20

Python工具代碼

2021-06-03 08:55:54

分布式事務(wù)ACID

2022-10-17 00:04:30

索引SQL訂單

2024-01-31 23:47:17

i++++i編碼

2023-01-03 18:06:42

高并發(fā)架構(gòu)

2020-12-03 07:39:50

HashMap底層數(shù)據(jù)

2024-02-28 10:14:47

Redis數(shù)據(jù)硬盤(pán)

2020-08-10 07:58:18

異步編程調(diào)用

2021-09-29 19:17:51

編碼URLEncodeGBK
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)