java中的 "+="运算符 与C的区别
问题概述
C语言中的 += 符号
大家在c语言的学习过程中,一定接触过 += 这个常见的运算符.。+= 属于复合赋值运算符的一种. 和 “+=” 同一类的符号还有 -= *= 等。他们的的运算规则也十分简单,如下面的例子:
#include<stdio.h>
int main(){
int m=3;
printf("%d",m+=2); //输出5
printf("m=%d",m); //输出m=5
return 0;
}
对于 m+=2 ,我们可以把它转换成式子 m=m+2 来看。对于这整个表达式,m的值 与 整个表达式 的值均被更新为 m+2 的值 。
不过在遇到多个 += 时,情况变得稍微复杂。本例仅给出多个 += 的情况。例子如下:
#include<stdio.h>
int main(){
int m=3;
printf("%d",m+=m+=2); //输出10
printf("m=%d",m); //输出m=10
return 0;
}
为什么会输出10?我们可以先将这个式子还原为易于人理解的情况。
表达式 | m的值 |
---|---|
m+=m+=2 | 3 |
m+=(m=m+2) | 3 |
m+=5 | 5 |
m=m+5 | 5 |
m | 10 |
可以看到,m的值在表达式计算的过程中在变动。每遇到一次+=, m的值都会变化
java中的+=符号
java 中也存在+=之类符号,用法和c也很相似。日常使用中我们可能不会知道他们的区别。
public class test {
public static void main(String []args) {
int m=3;
System.out.println(m+=2); //输出5
System.out.println("m="+m); //输出m=5
}
}
但是当我们按照c的规律递推时,则无法得出和c类似的结果。
public class test {
public static void main(String []args) {
int m=3;
System.out.println(m+=m+=2); //输出8
System.out.println("m="+m); //输出m=8
}
}
为什么呢?
初步分析
我们从java与c程序的结果可初步知道,m的值最终会与整个表达式的值相等。这也符合赋值运算符的计算规律。
做其他例子做出假设
我们可以先试着拆散这个式子,把这个式子拆成两段:
public class test {
public static void main(String []args) {
int m=3;
System.out.println(m+=m+=2); //输出8
System.out.println("m="+m); //输出m=8
//----------------将式子拆开--------------
int n=3;
n+=2; //第一步
System.out.println(n); //输出m=5
n+=n; //第二步
System.out.println(n); //输出m=10
}
}
结果是不是很熟悉? m在第一阶段为5,在第二阶段为10不正是C代码中计算的结果吗
我们可以做几个假设:
- java中+=这类的符号计算方向与c不同
- java中+=这类符号在连续使用时,变量变化规律与c不同
- java在计算表达式时,各项数值已经确定,并不会自动更新 (仅对于+=这类运算符)
检验假设
- java中+=这类的符号计算方向与c不同:
第一个假设很好验证,我们就拿原来的式子做验证。第一个假设很好验证,我们就拿原来的式子做验证。
表达式 | m的值 |
---|---|
m+=m+=2 | 3 |
(m+=m)+=2 | 3 |
m+=2 | 6 |
m | 9 |
结果和m=8明显不符。同时,当你在eclipse中输入 **(m+=m)+=2** 时,会发现编译器报错。
从编译器错误知道,式子m+=m 在计算以后返回的结果为数值,而数值并不能进行+=运算。这个假设明显不成立。
- java中+=这类符号在连续使用时,变量变化规律与c不同
- c语言代码中,m最明显的变化就是每遇到一次+=, m的值都会变化。会不会是这个问题?
会不会是在计算表达式时,各项数值已经确定,并不会自动更新的问题?
表达式 | m的值 |
---|---|
m+=m+=2 | 3 |
m+=5 | 3 |
m | 8 |
和结果m=8对应上了,那用这理论能否推算出其他式子结果呢?
public class test {
public static void main(String []args) {
int m=3;
System.out.println(m+=m+=m+=2); //结果为11
System.out.println("m="+m); //结果为11
}
}
这套理论应该是正确的
探求真理
虽然已经大致知道这段代码的运行方法,但是总是会有点担心会有问题。
这时我们可以用javap反编译工具找出代码运行的过程。
//test.java文件
class test{
public static void main(String []args){
int m=3;
m+=m+=2;
}
}
在cmd窗口中对test.java进行反编译
我们主要看的是main函数中,Code的内容
指令大全:https://blog.youkuaiyun.com/hudashi/article/details/7062675
指令 | 作用 |
---|---|
iconst_3 | 将int型(3)推送至栈顶 |
istore_1 | 将栈顶int型数值存入第二个本地变量 |
iload_1 | 将第二个int型本地变量推送至栈顶 |
iinc [变量] [参数] | 对变量进行自增操作,自增量为参数 |
istore_1 | 将栈顶int型数值存入第二个本地变量 |
iadd | 将栈顶两int型数值相加并将结果压入栈顶 |
详细解读
0: iconst_3
1: istore_1
2: iload_1
3: iinc 1, 2
6: iload_1
7: iadd
8: istore_1
详细情况:
行 | 栈(底>顶 ) | 变量 | 对应操作 |
---|---|---|---|
0 | 3 | 将int型(3)推送至栈顶 | |
1 | (1): 3 | 将栈顶int型数值存入第二个本地变量(m) | |
2 | 3 | (1):3 | 将第二个int型本地变量推送至栈顶 |
3 | 3 | (1):5 | 对本地变量(m)进行自增2操作 |
6 | 3 , 5 | (1):5 | 将第二个int型本地变量(m)推送至栈顶 |
7 | 8 | (1):5 | 将栈顶int型数值存入第二个本地变量(m) |
8 | (1):8 | 将栈顶int型数值存入第二个本地变量(m) |
由此我们可以知道,在计算+=符号前,java已经将式子拆散并确定了+=中的 自身变量 值。
在+=为5个的时候,我们能很清晰的看到确定值的过程
表达式 | m的值 | 对应操作行 |
---|---|---|
m+=m+=m+=m+=m+=2 | 3 | 0、1 |
m=( m=(m=(m=(m+=2 )+2 )+2 )+2 )+2 | 3 | 2、3、4、5 |
m=( m=(m=(m=(m+=2 )+2 )+2 )+2 )+2 | 5 | 6 |
m=( m=(m=(m=5+2 )+2 )+2 )+2 | 5 | 9 |
m=( m=(m=(m=7 )+2 )+2 )+2 | 5 | 10 |
m=( m=(m= | 5 | 11 |
m=( m=(m=7+2 )+2 )+2 | 7 | 12 |
m=( m=(m=9 )+2 )+2 | 7 | 13 |
m=( m= | 7 | 14 |
m=( m=9+2 )+2 | 9 | 15 |
m=( m=11 )+2 | 9 | 16 |
m=( | 9 | 17 |
m=11+2 | 11 | 18 |
m=13 | 11 | 19 |
m | 13 | 20 |
结论
java在计算+=的过程,可以近似看为展开。但计算表达式时,各项数值已经确定,并不会自动更新。