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

时间:2022-08-28 03:01:26

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