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;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=4, locals=2, args_size=10: iconst_21: istore_12: iload_13: iload_14: iload_15: iload_16: imul7: isub8: dup9: istore_110: iadd11: istore_112: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;15: new #3 // class java/lang/StringBuilder18: dup19: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V22: ldc #5 // String a=24: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;27: iload_128: 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;)V37: returnLineNumberTable:line 5: 0line 6: 2line 7: 12line 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的值。