提问人:Hex Crown 提问时间:3/21/2018 更新时间:3/24/2018 访问量:102
Java,“a[1] *= a[1] = b[n + 1]”没有按预期工作?
Java, "a[1] *= a[1] = b[n + 1]" not working as expected?
问:
正如标题所示,我有一个使用临时数组的函数,我想从另一个数组中将一个值写入其中,然后将这两个值与自身相乘。
例:
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.
既然如此,那岂不是表明我原来的例子应该有效吗?
谁能解释一下发生了什么以及为什么这段代码不能按预期工作?
答:
赋值运算符(与大多数其他运算符不同)在 Java 中从右到左计算(文档)。这意味着以下内容:
a[0] *= a[0] = b[n];
实际上被评估为:
a[0] *= (a[0] = b[n]);
括号中的数量是一个赋值,返回值 ,但不更改 的值。然后,进行以下最终分配:b[n]
a[0]
a[0] = a[0] * b[n]
两者都是赋值运算符,并且具有相同的优先级。因此,在这种情况下,从右到左的规则适用。*=
=
评论
a[0] *= (a[0] = b[n])
a[0] *= b[n]
(a[0] = b[n])
a[0]
b[n]
a[0] = b[n]*b[n]
b[n]
a[0]
参考 Java 文档:
除赋值运算符外,所有二元运算符都从左到右计算;赋值运算符从右到左计算。
因此,在您的案例中发生的情况是,您分配了 的值,然后将原始值乘以该新值。所以你的表情是有效的.a[0] *= a[0] = b[n ];
a[0]
b[n]
a[0]
a[0] *= b[n]
就个人而言,我不会在一行上两次使用赋值运算符,阅读起来可能会令人困惑。
评论
a=b=c
c
a
b
a[0]
a[0]
a[0] = b[n]
a[0](old) *= a[0](new)
a = b = c
b = c
a = b
a[0]
a[0](old)
我认为到目前为止的答案是不正确的。起作用的是复合表达式的计算,例如 。简而言之,左侧的值是在右侧之前计算的。来自 JLS(强调我的):a *= b
在运行时,通过以下两种方式之一计算表达式。
如果左侧操作数表达式不是数组访问表达式, 然后:
首先,计算左操作数以生成变量。如果 此计算突然完成,然后赋值表达式 出于同样的原因突然完成;右手操作数不是 已评估,并且不会发生赋值。
否则,将保存左侧操作数的值,然后 评估右手操作数。如果此评估完成 然后,赋值表达式突然完成 同样的原因,没有发生分配。
否则,左侧变量的保存值和 右侧操作数用于执行二进制运算 由复合赋值运算符指示。如果此操作 突然完成,然后赋值表达式突然完成 出于同样的原因,并且不会发生赋值。
否则,二进制操作的结果将转换为类型 左侧变量,进行值集转换 (§5.1.13) 到适当的标准值集(不是扩展指数值 set),转换结果将存储到变量中。
在您的示例中:
a[0] *= a[0] = b[n ];
- 的值计算并存储在 say 中
a[0]
tmp
a[0] = b[n]
被计算,给出 的值(并将 的值更改为b[n]
a[0]
b[n]
)tmp * a[0]
计算- 最后一步的结果被分配给
a[0]
所以,你得到的是有效的.a[0] *= b[n]
编辑:关于从右到左评估作业的混淆:我没有发现 JLS 中使用的术语,恕我直言,这是不正确的(尽管它在 Java 教程中使用)。它被称为 right-**associative* assJLS 对赋值是这样说的:
有 12 个赋值运算符;在句法上都是 右关联(他们从右到左分组)。因此,a=b=c 表示 a=(b=c),将 c 的值分配给 b,然后分配值 从 B 到 A。
评论
a *= b
a
a
a
*=
答案中似乎还没有指出的一个关键点是,它不仅仅是一个赋值运算符,而是一个复合赋值运算符。*=
语言规范说,以下内容是等效的:
E1 op= E2
<=>
E1 = (T) ((E1) op (E2))
哪里是类似的东西,等等。op=
*=
+=
因此:
a[0] *= a[0] = b[n ];
相当于:
a[0] = a[0] * (a[0] = b[n]);
并且 在 之前被计算,因为计算顺序是从左到右。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]
评论
a[0]=b[n]*b[n]