正如标题所示,我有一个使用临时数组的函数,我想从另一个数组中写入一个值,然后将这两个值与它们相乘。
示例:
float[] a = {0, 0}
a[0] *= a[0] = b[n ];
a[1] *= a[1] = b[n + 1];
我希望上面会做到以下几点:
a[0] = b[n ];
a[0] *= a[0]; //(aka: a[0] = a[0] * a[0])
a[1] = b[n + 1];
a[1] *= a[1];
虽然这种行为似乎没有发生。相反,它似乎只是乘以“a”中的原始值与“b”中保存的任何值相乘:
a[0] = a[0] * b[n ];
a[1] = a[1] * b[n + 1];
总是我的理解是,首先评估“=”之后的任何内容,如下所示:
float a, b;
a = b = 5;
//"a" and "b" both equal "5" now.
就是这样,是不是表明我原来的例子应该有效?
任何人都可以解释发生了什么以及为什么此代码无法正常工作?
答案 0 :(得分:7)
我认为到目前为止的答案并不正确。最重要的是评估像a *= b
这样的复合表达式。简而言之,左侧的值在右侧之前计算。来自JLS(强调我的):
在运行时,表达式以两种方式之一进行评估。
如果左侧操作数表达式不是数组访问表达式, 然后:
首先,评估左侧操作数以生成变量。如果 此评估突然完成,然后是赋值表达式 因同样的原因突然完成;右手操作数不是 评估并且没有分配。
否则,保存左侧操作数的值,然后保存 评估右侧操作数。如果此评估完成 然后突然完成赋值表达式 同样的原因,没有任何转让。
否则,保存左侧变量的值和值 右侧操作数用于执行二进制操作 由复合赋值运算符表示。如果这个操作 突然完成,然后赋值表达式突然完成 出于同样的原因,没有任何转让。
否则,二进制操作的结果将转换为该类型 左侧变量的值,经过值集转换(§5.1.13) 到适当的标准值集(不是扩展指数值) set),转换结果存储在变量中。
在你的例子中:
a[0] *= a[0] = b[n ];
a[0]
的值,并将其存储在tmp
a[0] = b[n]
,给出b[n]
的值(并将a[0]
的值更改为b[n]
)tmp * a[0]
a[0]
所以,你得到的是a[0] *= b[n]
。
编辑:关于从右到左 - 评估分配的混淆:我没有找到JLS中使用的术语,恕我直言,这是不正确的(尽管它在Java教程中使用)。它被称为正确 - ** associative * assThe JLS说这是关于任务的:
有12个赋值运算符;一切都是语法上的 右联想(他们从右到左分组)。因此,a = b = c表示 a =(b = c),它将c的值赋给b,然后赋值 b到a。
答案 1 :(得分:3)
参考Java documentation:
除了赋值运算符之外的所有二元运算符都是从左到右计算的;赋值运算符从右到左进行求值。
因此,a[0] *= a[0] = b[n ];
的情况是,您为a[0]
分配b[n]
的值,然后将原始a[0]
乘以该新值。所以你的表达有效a[0] *= b[n]
。
就个人而言,我不会在一行上使用赋值运算符两次,这可能会令人困惑。
答案 2 :(得分:2)
分配运算符(与大多数其他运算符不同)在Java(documentation)中从右到左进行评估。这意味着以下内容:
a[0] *= a[0] = b[n];
实际上被评估为:
a[0] *= (a[0] = b[n]);
括号中的数量是一项赋值,并返回值b[n]
,但不会更改a[0]
的值。然后,进行以下最终分配:
a[0] = a[0] * b[n]
*=
和=
都是赋值运算符,并且具有相同的优先级。因此,在这种情况下,适用从右到左的规则。
答案 3 :(得分:0)
答案中似乎没有指出的关键点是*=
不仅仅是一个赋值运算符,而是一个复合赋值运算符。 / p>
The language spec表示以下内容相同:
E1 op= E2
<=>
E1 = (T) ((E1) op (E2))
其中op=
类似于*=
,+=
等。
因此:
a[0] *= a[0] = b[n ];
相当于:
a[0] = a[0] * (a[0] = b[n]);
由于left-to-right evaluation order,和a[0]
在(a[0] = b[n])
之前进行了评估。
所以:
a[0]
读取值(称之为“A
”)b[n]
读取值(称之为“B
”)B
分配给a[0]
(*)A * B
(称之为“C
”)C
存储回a[0]
。所以是的,这相当于将a[0]
中的任何内容乘以b[n]
,因为上面标记为(*)的步骤是多余的:在重新分配之前,永远不会读取分配给它的值。 / p>