看一些JAVA基礎題的時候,經常看到這個問題,很多人的解釋是:i++最快,i+=1其次,i=i+1最慢。下面通過Sun JDK編譯出來的位元組碼驗證一下這個問題。
為了讓編譯出來的位元組碼便於閱讀,將這三個表示式分別寫在一個方法裡面:
1 private void a(){ 2 int i=0; 3 i += 1; 4 } 5 6 private void b(){ 7 int i=0; 8 i++; 9 } 10 11 private void c(){ 12 int i=0; 13 i=i+1; 14 }
編譯之後(SUN JDK1.7),再看編譯出來的位元組碼(直接把.class檔案用IDE開啟,或者用javap -v -p classFileName命令):
// Method descriptor #6 ()V // Stack: 1, Locals: 2 private void a(); 0 iconst_0 1 istore_1 [i] 2 iinc 1 1 [i] 5 return Line numbers: [pc: 0, line: 15] [pc: 2, line: 16] [pc: 5, line: 17] Local variable table: [pc: 0, pc: 6] local: this index: 0 type: com.leo.javabasis.Add [pc: 2, pc: 6] local: i index: 1 type: int // Method descriptor #6 ()V // Stack: 1, Locals: 2 private void b(); 0 iconst_0 1 istore_1 [i] 2 iinc 1 1 [i] 5 return Line numbers: [pc: 0, line: 20] [pc: 2, line: 21] [pc: 5, line: 22] Local variable table: [pc: 0, pc: 6] local: this index: 0 type: com.leo.javabasis.Add [pc: 2, pc: 6] local: i index: 1 type: int // Method descriptor #6 ()V // Stack: 1, Locals: 2 private void c(); 0 iconst_0 1 istore_1 [i] 2 iinc 1 1 [i] 5 return Line numbers: [pc: 0, line: 25] [pc: 2, line: 26] [pc: 5, line: 27] Local variable table: [pc: 0, pc: 6] local: this index: 0 type: com.leo.javabasis.Add [pc: 2, pc: 6] local: i index: 1 type: int
這三個方法的位元組碼是一樣的(除了行號),先稍微解釋一下這段位元組碼指令:
iconst_0 //整數常量0入棧
istore_1 //將棧上的值出棧,儲存到序號為1的區域性變數(也就是i)
iinc 1 1 //將序號為1的區域性變數增加1,此指令語法為iinc index const。
是不是SUN JDK在某一個版本之前是沒有對這個問題進行優化?找了一個能用的SUN JDK 1.3再試了一下(1.1, 1.2跑不動了),編譯出來的結果,方法a、b的位元組碼和1.7下是一樣的。但是c的就不一樣了:
Method void c() 0 iconst_0 1 istore_1 2 iload_1 3 iconst_1 4 iadd 5 istore_1 6 return
指令行2-5的作用分別是:
iload_1 //將序號為1的區域性整數變數入棧
iconst_1 //整數常量1入棧
iadd //使用棧上的兩個整數值出棧進行加法運算,將結果入棧
istore_1 //將棧上的整數值儲存到序號為1的區域性變數
這種方式同樣達到了相加的目的,但是相比直接iinc指令,還是繞了很多,效率自然不會好。
由此看來,在某一個版本之後,編譯器是對這個問題進行了優化。關於誰的效率好的問題,在現在的SUN JDK版本中已經沒有差別了(即使是使用1.7的JDK編譯出的1.3JRE相容的位元組碼,方法c也是優化過的),
但是曾經某個時代確實是有差別的。