class Hello {
public static void main(String args[]) {
int i = 10;
i *= i++ + i;
System.out.println(i);
}
}
根据运算符优先级,后缀运算符的优先级高于乘法运算符。括号内的操作数有更多优先权。
首先评估它们:i *(i ++ + i) 那么,现在,括号内是10 + 11:i *(21)
i的当前值是11
其次,由于下一个优先级而对乘法运算符求值,是不是11 * 21 = 231?
虽然,我知道答案是210,为什么我上面解释的逻辑错了?
答案 0 :(得分:4)
将其拆分为以下
i = i * (i++ + i);
现在,你有:
i = 10 * (i++ + i);
然后,你有:
i = 10 * (10 + i);
然后,你有:
i = 10 * (10 + 11);
然后,你有:
i = 10 * (21);
然后,你有:
i = 210;
正如您所看到的," i"首先加载,然后完成剩余的计算,而不是相反。
编辑: 介于两者之间,i的值也设置为11,因此数字为#11; 11"在第4步,但在那之后,它会在最后被覆盖,所以这个值不再重要。
交换计算将产生您想要的结果:
i = (i++ + i) * i;
答案 1 :(得分:1)
首先要注意的是,您没有进行简单的乘法,而是使用compound assignment operator
,这是一个封装对变量执行操作然后分配变量的运算符。结果是原始变量。
来自JLS section about compound assignment operators(例如*=
):
首先,评估左侧操作数以生成变量。如果 此评估突然完成,然后是赋值表达式 因同样的原因突然完成;右手操作数不是 评估并且没有分配。
否则,保存左侧操作数的值,然后保存 评估右侧操作数。如果此评估完成 然后突然完成赋值表达式 同样的原因,没有任何转让。
- 否则,左侧变量的保存值和右侧操作数的值用于执行复合赋值运算符指示的二进制运算。如果此操作突然完成,则赋值表达式会因同样的原因突然完成,并且不会发生任何分配。
突出显示的文本保证在乘法的左侧将使用i
的原始值,即10.(右侧评估为21,正如您已正确推导的那样。)
另一个可以说更重要的教训是运算符优先级与评估顺序不同。优先级仅用于将表达式解析为表达式树,但始终从左到右,从外部对运算符进行求值。
在你的情况下,表达式树看起来大致如下(注意最低优先级运算符如何在树的根处结束):
*=
/ \
i +
/ \
i++ i
...现在它从上到下,从左到右进行评估:
*= *= *= *= 210
/ \ / \ / \ / \
10 + -> 10 + -> 10 + -> 10 21 ->
/ \ / \ / \
i++ i 10 i 10 11
答案 2 :(得分:0)
仅仅因为运算符必须按特定顺序应用,并不意味着必须首先评估最高优先级运算符的直接操作数。
事实上,这里适用的规则是:
Java编程语言保证运算符的操作数似乎以特定的评估顺序进行评估,即从左到右。在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已完全评估。2011年7月23日
除非你遵循一个简单的规则,否则这可能会非常混乱:不要嵌入副作用会影响计算中间操作数的子表达式,因为它会使你的代码无法读取。
答案 3 :(得分:0)
int i = 10;
i *= i++ + i;
i = i * (i++ +i)
i++
会增加i
的值,但会在递增之前返回i
所持有的原始值。
i = 10;
j = i++;
(i is 11, j is 10)
所以,你有:
i = 10 * (10 + 11);
i = 10 * (21)
i = 210
所以,你的答案是:210
。