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

时间:2012-11-22 21:07:18

标签: java operators operator-precedence

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

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

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

什么是=+运营商?

什么是+++运营商?

什么是- -运营商?

什么是|=运营商?

4 个答案:

答案 0 :(得分:191)

  

什么是=+运营商?

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

您是否拼错了并且指的是复合赋值运算符+=

  

什么是+++运营商?

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

  

什么是- -运营商?

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

  

什么是|=运营商?

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

a |= b;

几乎相当于

a = a | b;

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

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

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

第一行相当于

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

赋值(例如i = 0)求值为存储的值(此处为i)。

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

return i |= (j |= (k |= (((j += i) - (-(k++ + k))) - (-(i = +j)))));
  • i |= stuff_1i被评估(0),stuff_1被评估,按位或被采用,结果存储在i中。由于i最初为0,因此相当于i = stuff_1

  • j |= stuff_2j被评估(2),stuff_2被评估,按位或被采用,结果存储在j。< / p>

  • k |= stuff_3k从左到右进行评估(3),然后stuff_3

    • (j += i)i添加到j,将总和存储在j中,并返回j的新值。 由于i为0,j不会更改,值为2。
    • (k++ + k)获取旧值k(3),增加k并添加k的新值(4),结果为7.该值为否定,从2中减去否定值(-7),得到2 - (-7) = 9
    • (i = +j)j(2)的值存储在i中,表达式的值也是2.该值被否定(-2)并从中减去我们从前面的操作得到的9,所以stuff_3评估为11,副作用是

      • i的存储值现在为2
      • j的存储值现在为2(实际上没有变化,因为i最初为0)
      • k的存储值现在为4
    • k(3)的旧值按位或按11,结果为11,存储在k中,11为stuff_2的值,是k |= stuff_3
  • j(2)的旧值与stuff_2(11)的值按位或按位,结果为11.该值存储在j中,stuff_1j |= stuff_2)的值为11。

  • i(0)的旧值与stuff_1(11)的值按位或取值,结果存入i,且值为i |= stuff_1为11.然后返回该值。

答案 1 :(得分:42)

原始开发者已不再可用,我无法理解。

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

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

括号&amp;运算符优先级,评估为:

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

返回i | = j | = k | =(j + = i) - - (k +++ k) - - (i = + j);

扩展&#34; | =&#34;运营商,这相当于:

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

左边&#34; |&#34;始终首先评估运算符并记住,因此将变量值替换为左侧:

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

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

(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

答案 2 :(得分:18)

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

  

将其替换为return 11;并提交。

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

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

答案 3 :(得分:16)

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

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