我在一个我开始研究的项目中遇到了这段代码。最初的开发人员已经不再可用了,我无法理解它:
k = (j = (i = 0) + 2) + 1;
return i|= j|= k|= (j+= i) - - (k+++k) - - (i =+j);
它产生的值为11
。这是如何运作的?
什么是=+
运营商?
什么是+++
运营商?
什么是- -
运营商?
什么是|=
运营商?
什么是
=+
运营商?
这是两个运算符,一个赋值运算符,=
和一个一元加号+
,它什么都不做。
你输入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_1
:j |= stuff_2
被评估(2),j
被评估,按位或被采用,结果存储在stuff_2
中。j
:k |= 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减去,导致k
。
2 - (-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
中,j
(stuff_1
)的值为11。j |= stuff_2
(0)的旧值与i
(11)的值按位或结合,结果存储在stuff_1
中,i
的值为11.然后返回该值。最初的开发人员已经不再可用,我无法理解它。
最初的开发人员故意在代码中留下了一个曲折的任务问题。这与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) ) ) );
对我来说,最好的答案是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在方法之外可见并在其他地方重复使用。但这不太可能。
您的程序在C中调用未定义的行为。您正在两个序列点之间多次修改return 11;
和i
。
在Java和JavaScript中,行为是明确定义的,您必须查看运算符的优先级和关联性。