为什么i | = j | = k | =(j + = i) - - (k +++ k) - - (i = + j)== 11?

问题描述 投票:-77回答:4

我在一个我开始研究的项目中遇到了这段代码。最初的开发人员已经不再可用了,我无法理解它:

k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);

它产生的值为11。这是如何运作的?

什么是=+运营商?

什么是+++运营商?

什么是- -运营商?

什么是|=运营商?

java operators operator-precedence
4个回答
195
投票

什么是=+运营商?

这是两个运算符,一个赋值运算符,=和一个一元加号+,它什么都不做。

你输入o并且表示复合赋值运算符qazxsw poi吗?

什么是+=运营商?

还有两个运算符,一个后增量,+++和一个加法,++,(根据最大的munch规则,选择最长的有效令牌,如果选择了最短的有效令牌,它将成为一个加法和两个一元加号)。

什么是+运营商?

再两个运算符,一个减法和一个一元减(否定)。

什么是- -运营商?

复合赋值,按位[或者,在|=值的情况下,逻辑运算]左侧值与右侧值并将其存储在左侧变量中。

boolean

几乎相当于

a |= b;

但是左侧操作数只被评估一次,后者可能需要一个显式的强制转换,而前者则不需要。

a = a | b;

它产生的值为11.这是如何工作的?

第一行相当于

k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);

赋值(例如i = 0; j = i+2; k = j+1; )求值为存储的值(在i = 0中)。

下一行是适当的间距,并添加了隐式括号

i
  • return i |= (j |= (k |= (((j += i) - (-(k++ + k))) - (-(i = +j))))); i |= stuff_1被评估(0),i被评估,按位或被采用,结果存储在stuff_1中。由于i原为0,这相当于i
  • i = stuff_1j |= stuff_2被评估(2),j被评估,按位或被采用,结果存储在stuff_2中。
  • jk |= stuff_3被评估(3),然后是k,从左到右。 stuff_3(j += i)添加到i,将总和存储在j并返回j的新值。由于j为0,i不会改变,值为2。 j(k++ + k)(3)的旧值,增加k并添加k的新值(4),得到7.该值被否定,并且否定值(-7)从2减去,导致k2 - (-7) = 9(i = +j)(2)的值存储在j中,并且表达式的值也是2.该值被否定(-2)并从我们从前面的操作中得到的值中减去,因此i的计算结果为11,其中效果 stuff_3的储值现在是2 i的存储值现在为2(实际上没有变化,因为j最初为0) i的储值现在是4 k(3)的旧值按位或按11,得到11,存储在k中,11是k的值,即stuff_2
  • k |= stuff_3(2)的旧值与j(11)的值按位或取值,得到11.值存储在stuff_2中,jstuff_1)的值为11。
  • j |= stuff_2(0)的旧值与i(11)的值按位或结合,结果存储在stuff_1中,i的值为11.然后返回该值。

44
投票

最初的开发人员已经不再可用,我无法理解它。

最初的开发人员故意在代码中留下了一个曲折的任务问题。这与Daniel Fischer给出的答案完全相同,但为了清楚地解释,我将按照与评估顺序相对应的步骤进行评估。

k =(j =(i = 0)+ 2)+ 1;

括号和运算符优先级,评估为:

i |= stuff_1

return i | = j | = k | =(j + = i) - - (k +++ k) - - (i = + j);

扩展“| =”运算符,这相当于:

i = 0;    
j = i + 2;  // j = 2
k = j + 1;  // k = 3

左边的“|”始终首先评估运算符并记住,因此将变量值替换为左侧:

return i = i | ( j = j | ( k = k | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );

然后评估每个“|”的右侧运算符(带括号,运算符和从左到右的优先级):

return i = 0 | ( j = 2 | ( k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) ) ) );

18
投票

对我来说,最好的答案是Mike Rylander(评论中)。

(j+= i): pre-increments j = j + i; // j = 2 + 0 = 2 then expression evaluates to j // evaluates to 2 (k+++k): first evaluates k++ // sub-expression evaluates to 3, // then post-increments k: k = 4 then evaluates (k++)+k // evaluates to 3+4 = 7 (i =+ j): "=+" is not an java operator!! it is evaluated as "=" operator followed by unary "+" operator expression evaluates to +j // evaluates to 2 k = 3 | ( (j+= i) - - (k+++k) - - (i =+j) ) = 3 | ( 2 - -7 - -2) = 3 | 11 = (2+1) | (8+2+1) = (8+2+1) = 11 j = 2 | k = 2 | 11 = (2) | (8+2+1) = 8+2+1 = 11 i = 1 | j; = 1 | 11 = (1) | (8+2+1) = 8+2+1 = 11 return i; // return 11 替换它并提交。

我的意思是,代码不依赖于之前编写的任何内容,因此每次生成11。这是一个复杂的计算,需要花费时间,并产生11.所以你只需要返回11.不要保留开发人员的无用代码,他们显然对你很开心。它让我想起了一位前同事,他在代码中设置了炸弹(很少崩溃,但有时甚至崩溃),就在辞职之前......

注意:可能存在不等效的情况:如果i,j和k在方法之外可见并在其他地方重复使用。但这不太可能。


16
投票

您的程序在C中调用未定义的行为。您正在两个序列点之间多次修改return 11;i

在Java和JavaScript中,行为是明确定义的,您必须查看运算符的优先级和关联性。

© www.soinside.com 2019 - 2024. All rights reserved.