Java面试:a+=a-=a*a原理解析
a+=a-=a*a属于Java基础中比较难以理解的,面试中也经常会遇到这个问题,本篇博客对此问题进行分享总结。
1.问题代码
public static void main(String[] args) {
int a = 2;
a+=a-=a*a;
System.out.println("a="+a);
}
我第一次遇见这个问题的时候,很不巧的算错了结果还和运行结果一致。在后面梳理思路时发现其中问题,反编译class文件才明白其中原理,感觉是个很有意思的问题。下面给出运行结果
到这很多同学开始疑惑了吧,结果为什么不是-4。接下来看看JVM如何运行这段代码的。
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=2, args_size=1
0: iconst_2
1: istore_1
2: iload_1
3: iload_1
4: iload_1
5: iload_1
6: imul
7: isub
8: dup
9: istore_1
10: iadd
11: istore_1
12: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
15: new #3 // class java/lang/StringBuilder
18: dup
19: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
22: ldc #5 // String a=
24: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: iload_1
28: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
31: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
37: return
LineNumberTable:
line 5: 0
line 6: 2
line 7: 12
line 8: 37
}
这是用javap -verbose反编译的代码。
先看指令号为2、3、4、5完成的事情,这四行指令完成了将运算需要的数据加载到操作数栈中。
指令号6(imul)将栈顶两int型数值相乘并将结果压入栈顶
指令号7(isub)将栈顶两int型数值相减并将结果压入栈顶
指令号8(dup)复制栈顶数值并将复制值压入栈顶
指令号9(istore_1) 将栈顶int型数值存入局部变量表第二个位置,第一个赋值操作出现了。
关键点出现了,指令号10(iadd)将栈顶两个int值相加操作数栈现在只有-2和2,明显a+=a-=a*a中a+=的a并没有重新去栈中取值,准确的说四个a的值在计算开始时已经全部取出。所以最后相加的时候,用的是刚开始时定义的a的值。