我正在阅读一些Java文本并获得以下代码:
int[] a = {4,4};
int b = 1;
a[b] = b = 0;
在文中,作者没有给出明确的解释,最后一行的效果是:a[1] = 0;
我不太清楚我理解:评估是如何发生的?
答案 0 :(得分:166)
答案 1 :(得分:33)
Eric Lippert的精湛答案虽然不是很有帮助,因为它正在谈论另一种语言。这是Java,其中Java语言规范是语义的权威描述。特别是,§15.26.1是相关的,因为它描述了=
运算符的评估顺序(我们都知道它是右关联的,是吗?)。在这个问题中将它减少到我们关心的位:
如果左侧操作数表达式是数组访问表达式(§15.13),则需要执行许多步骤:
- 首先,评估左侧操作数数组访问表达式的数组引用子表达式。如果此评估突然完成,则赋值表达式出于同样的原因突然完成;索引子表达式(左侧操作数数组访问表达式)和右侧操作数未被评估,也不会发生任何赋值。
- 否则,将评估左侧操作数数组访问表达式的索引子表达式。如果此评估突然完成,则赋值表达式会出于同样的原因突然完成,并且不会评估右侧操作数并且不会发生任何赋值。
- 否则,将评估右侧操作数。如果此评估突然完成,则赋值表达式会因同样的原因而突然完成,并且不会发生任何分配。
[...然后继续描述赋值本身的实际含义,为简洁起见,我们可以忽略这一点......]
简而言之,Java有一个非常严格定义的evaluation order,它在任何运算符或方法调用的参数中几乎都是从左到右。数组赋值是更复杂的情况之一,但即便如此,它仍然是L2R。 (JLS确实建议您不要编写需要这些复杂语义约束的代码,我也是如此:每个语句只需要一个赋值,就会遇到很多麻烦!)< / p>
C和C ++在这方面肯定与Java不同:它们的语言定义会故意定义评估顺序以实现更多优化。 C#显然与Java类似,但我不能很好地了解它的文献,无法指出正式的定义。 (这确实因语言而异,Ruby严格来说是L2R,就像Tcl一样 - 虽然缺少一个赋值运算符本身,原因与这里不相关 - 而Python是L2R but R2L in respect of assignment,我发现奇怪,但你去。)
答案 2 :(得分:5)
a[b] = b = 0;
1)数组索引运算符的优先级高于赋值运算符(参见this answer):
(a[b]) = b = 0;
2)根据15.26。 JLS
的分配运算符有12个赋值运算符;所有这些都是语法上的右关联(他们从右到左分组)。因此,a = b = c表示a =(b = c),它将c的值赋给b,然后将b的值赋给a。
(a[b]) = (b=0);
3)根据15.7。评估顺序JLS
Java编程语言保证运算符的操作数似乎以特定的评估顺序进行评估,即从左到右。
和
在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已完全评估。
所以:
a)(a[b])
首先评估为a[1]
b)然后(b=0)
评估为0
c)(a[1] = 0)
最后评估
答案 3 :(得分:1)
您的代码相当于:
int[] a = {4,4};
int b = 1;
c = b;
b = 0;
a[c] = b;
解释了结果。
答案 4 :(得分:-1)
考虑下面另一个更深入的例子。
最好在解决这些问题时提供一份“优先顺序规则和关联性”表格,例如: http://introcs.cs.princeton.edu/java/11precedence/
这是一个很好的例子:
System.out.println(3+100/10*2-13);
问题:上述线路的输出是什么?
答案:应用优先权和相关性规则
步骤1:根据优先规则:/和*运算符优先于+ - 运算符。因此,执行此等式的起点将缩小为:
100/10*2
步骤2:根据规则和优先级:/和*优先级相等。
由于/和*运算符的优先级相同,我们需要查看这些运算符之间的关联性。
根据这两个特定运营商的ASSOCIATIVITY RULES, 我们从LEFT TO RIGHT开始执行等式,即首先执行100/10:
100/10*2
=100/10
=10*2
=20
步骤3:等式现在处于以下执行状态:
=3+20-13
根据规则和优先顺序:+和 - 优先级相等。
我们现在需要查看运算符+和 - 运算符之间的关联性。根据这两个特定运营商的相关性, 我们开始执行从LEFT到RIGHT的等式,即首先执行3 + 20:
=3+20
=23
=23-13
=10
编译时10是正确的输出
同样,在解决这些问题时,重要的是要有一张优先顺序规则和相关性表格,例如: http://introcs.cs.princeton.edu/java/11precedence/