JAVA的i++, i+=1, i=i+1有区别吗?

看一些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也是优化过的),
但是曾经某个时代确实是有差别的。



原文地址:https://www.cnblogs.com/leolztang/p/5469506.html