JAVA的i++, i+=1, i=i+1有區別嗎?

leolztang發表於2013-07-07

看一些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也是優化過的),
但是曾經某個時代確實是有差別的。



 

相關文章