class Output
{
public static void main (String[] args)
{
int a = 5;
a += 5+ (++a) + (a++);
System.out.print(a);
}
}
评价:
a += 5 + (++a) + (a++)
=> a+= 5 + 6 + (a++) [++a :increment value of a and then use it. So:increment a = 6, then use a=6]
=> a+= 5 + 6 + 6 [a++ :use and then increment value of a. So: use a=6, then increment a=7]
=> a+= 11 + 6
=> a+= 17
=> a = a+17
=> a = 7 + 17
=> a = 24
+=
操作符,像所有复合操作符一样,在计算所有其他操作数之前,在实际执行任何操作之前,先计算左侧第一个上的变量。这是由JLS第15.26.2节指定的:
如果左操作数表达式不是数组访问表达式,则:
- 首先,计算左操作数以产生一个变量。如果这个求值突然完成,那么赋值表达式也会因为同样的原因突然完成;右操作数不求值,也不赋值。
- 否则,保存左操作数的值然后计算右操作数。如果这个求值突然完成,那么赋值表达式也会因为同样的原因突然完成,并且不会发生赋值。
- 否则,将左侧变量的保存值和右侧操作数的保存值用于执行复合赋值操作符指定的二进制操作。如果这个操作突然完成,那么赋值表达式也会因为同样的原因突然完成,并且不会发生赋值操作。
- 否则,将二进制运算的结果转换为左侧变量的类型,并进行值集转换(§5.1.13)到适当的标准值集(不是扩展指数值集),并将转换的结果存储到变量中。
(粗体强调我的)
这意味着a
在左侧计算(并保存)为5
,然后在右侧计算a++
和++a
。右边的值是17
,但因为左边仍然是5
,所以和是22
,而不是24
。
表达式
a += 5 + (++a) + (a++);
等价于
a = a + 5 + (++a) + (a++);
意味着a
的新赋值是从右到左(因为从左到右结合性)的操作数的和,按以下方式求值:
- 取变量
a
:求值为5 - 添加常量
5
- 增加变量
a
和,然后评价结果:6 - 对变量
a
和求值,然后增量。在求和中使用的值将是求值: 6
和为22
。