增量逻辑
我试图更深入的后置和预增量器,但有点卡住了下面的expression式:
public static void main(String[] args) { int i = 0; i = i+=(++i + (i+=2 + --i) - ++i); // i = 0 + (++i + (i+=2 + --i) - ++i); // i = 0 + (1 + (3 + 2) - 1); // i = 0 + (6 - 1); System.out.println(i); // Prints 0 instead of 5 }
我知道我错过了逻辑的地方,但在哪里?
我试过了:
- 从左到右(尽pipe我知道不推荐)
- 从最内侧的支架开始,从那里开始。
谢谢您的帮助
PS:评论是我的微积分的细节
编辑1
我试图把expression式从硬编码值改为2
,结果总是为0
看看这个例子:
int i = 0; i = i+=(++i + (i+=32500 + --i) - ++i); System.out.println(i); // Prints 0
这个expression式在逻辑上应该远不是0
但它打印出来。
当我使用否定的时候会发生同样的情况:
int i = 0; i = i+=(++i + (i+=(-32650) + --i) - ++i); System.out.println(i); // Prints 0
编辑2
现在,我改变了我的价值开始:
int i = 1; i = i+=(++i + (i+=2 + --i) - ++i); System.out.println(i); // Prints 2 i = 2; i = i+=(++i + (i+=10000 + --i) - ++i); System.out.println(i); // Prints 4 i = 3; i = i+=(++i + (i+=(-32650) + --i) - ++i); System.out.println(i); // Prints 6
无论硬编码值是多less,它都会给i
每次的两倍。
引用Java语言规范,15.7评估顺序 :
Java编程语言保证操作符的操作数看起来是按照特定的评估顺序,即从左到右进行评估的。
二元运算符的左侧操作数似乎在评估右侧操作数的任何部分之前被充分评估。
如果操作符是复合赋值操作符 (第15.26.2节 ),则对左侧操作数的求值包括记住左侧操作数表示的variables和提取并保存该variables的值 ,以用于隐含的二进制操作。
所以,本质上, i += ++i
会记住左边的i
的旧值, 然后再评估右边。
请记住,操作数的评估顺序和操作符的优先级是两个不同的东西。
显示评估订单,一步一步,在{大括号}中保存值:
int i = 0; i = i += (++i + (i += 2 + --i) - ++i); // i = 0 i{0} = i += (++i + (i += 2 + --i) - ++i); // i = 0 i{0} = i{0} += (++i + (i += 2 + --i) - ++i); // i = 0 i{0} = i{0} += (1 + (i += 2 + --i) - ++i); // i = 1 i{0} = i{0} += (1 + (i{1} += 2 + --i) - ++i); // i = 1 i{0} = i{0} += (1 + (i{1} += 2 + 0 ) - ++i); // i = 0 i{0} = i{0} += (1 + (i{1} += 2 ) - ++i); // i = 0 i{0} = i{0} += (1 + 3 - ++i); // i = 3 i{0} = i{0} += (4 - ++i); // i = 3 i{0} = i{0} += (4 - 4 ); // i = 4 i{0} = i{0} += 0 ; // i = 4 i{0} = 0 ; // i = 0 0 ; // i = 0
跟进编辑问题
如果我们命名初始值I
和常数N
:
int i = I; i = i += (++i + (i += N + --i) - ++i);
那么我们可以看到这个值是:
i{I} = i{I} += ((I+1) + (i{I+1} += N + I) - ((I+1+N+I)+1)); i{I} = i{I} += (I + 1 + (I + 1 + N + I) - (I + 1 + N + I + 1)); i{I} = i{I} += (I + 1 + I + 1 + N + I - I - 1 - N - I - 1); i{I} = i{I} += I; i{I} = I + I; i = 2 * I;
这是考虑到您的第一次编辑(与未知的X
)的逻辑:
public static void main(String[] args) { int i = 0; i = i+=(++i + (i+=X + --i) - ++i); // i = 0 += (++i + ((i += (X + --i)) - ++i)); // i = 0 += (1 + ((i += (X + --i)) - ++i)); // i = 1 // i = 0 += (1 + ((1 += (X + --i)) - ++i)); // i = 1 and i will then take the result of 1 += (X + --i) // i = 0 += (1 + ((1 += (X + 0)) - ++i)); // i = 0 and i will then take the result of 1 += (X + 0) // i = 0 += (1 + (X + 1 - ++i)); // i = X + 1 // i = 0 += (1 + (X + 1 - X - 2)); // i = X + 2 // i = 0 += (0); // i = X + 2 // i = 0; System.out.println(i); // Prints 0 }
技巧在这里:
-
+=
是一个assignement操作符,所以它是正确的联想:在片段中,我加了括号来表示这个更清楚 - 赋值expression式的结果是赋值发生后variables的值
- 后缀增量运算符
++
和后缀减量运算符--
从值中加1或减1,结果存储回variables中。 -
+
加法运算符首先计算左边的操作数,然后计算右边的操作数。
为了您的第二次编辑(与I
未知的添加):
public static void main(String[] args) { int i = I; i = i+=(++i + (i+=X + --i) - ++i); // i = I += (++i + ((i += (X + --i)) - ++i)); // i = I += (I+1 + ((i += (X + --i)) - ++i)); // i = I+1 // i = I += (I+1 + ((I+1 += (X + --i)) - ++i)); // i = I+1 and i will then take the result of I+1 += (X + --i) // i = I += (I+1 + ((I+1 += (X + I)) - ++i)); // i = I and i will then take the result of I+1 += (X + I) // i = I += (I+1 + (X+2*I+1 - ++i)); // i = X + 2*I + 1 // i = I += (I+1 + (X+2*I+1 - X-2*I-2)); // i = X + 2*I + 2 // i = I += (I); // i = X + 2*I + 2 // i = 2 * I; System.out.println(i); // Prints 2 * I }
我build议如下:以不同的方式格式化代码,以便每行只有一条语句,例如
@Test public void test() { int i = 0; i = i+= ( ++i + ( i+= 2 + --i ) - ++i ); System.out.println(i); // Prints 0 instead of 5 }
然后在debugging器下运行,并总是按F5(“进入”)。 这将帮助您了解项目评估的顺序:
-
int i=0;
-
i=
:…(需要等待计算结果A) -
i+=
…(需要等待B) -
++i
:i = 1 -
i+=
…(需要等待C) -
2+
-
--i
:i = 0 - …:我= 3(等待的结果C)
-
-
-
++i
:i = 4, – 的操作数也是4 - …:i = 0(等待B的结果)
- …:i = 0(等待A的结果)
第10行总是使第3行的结果为0
,所以i的初始值不会被整个操作改变。
好吧,让我们分解一切:
int i = 0; // i = 0, no big deal
然后开始进入最内括号:
(i+=2 + --i)
- 它首先递减
i
并使用结果(-1
) - 然后加2(
-1+2=1
) - 并将结果添加到i(在操作开始时为
0+1=1=i
)(0+1=1=i
)
最后,第一次递减被重新分配忽略了。
下一个括号:
i+= (++i + previous_result - ++i)
- 它在两点增加
i
(用++i
) - 那么操作变成
(i+1) + previous_result - (i+2)
(注意增量不是同时的),给出2 + 1 - 3 = 0
。 - 该操作的结果被添加到初始的
i
(0
)
再次增加将被重新分配丢弃。
最后:
i = previous_result
哪给出0 🙂
我追溯了我的价值,这里是结果:
i = i+=(++i + (i+=2 + --i) - ++i); initialization: i = 0; ++i: i = 1;(1st one) and store this value (i+=2 + --i): In it --i: i = 0;(i was changed by the previous ++i) i += 2 + 0: i = 2;(value of the inner (i+=2 + --i), store it) ++i: i = 3; 1 + 2 -3: i = 0; i += 0: i = 0;
左边第二个i的值不是零,这是在所有右边的操作完成后i的值。
由于优先级最高(…)将先评估,然后++和 – 然后剩下的运营商。 你的表情就像
i = i += ( (++i) + (i+=2 + (--i)) - (++i) ); //i = i = i + ( (++i) + (i+=2 + (--i)) - (++i) ); //i = i = 0 + ( (++i) + (i+=2 + (--i)) - (++i) ); //i = i = 0 + ( (1) + (i+=2 + (--i)) - (++i) ); //i = i = 0 + ( (1) + (i+=2 + (0)) - (++i) ); //i = i = 0 + ( (1) + (2 + (0)) - (++i) ); //i = i = 0 + ( (1) + (2) - (++i) ); //i = i = 0 + ( (1) + (2) - (3) ); //i = i = 0 + ( 3 - 3 ); //i = i = 0 + ( 0 ); //i = 0
请完全加上你的表情。 你会明白expression的评价顺序。
为你的编辑1
i = i+=( (++i) + (i+=32500 + (--i) ) - (++i) ); // 0 + ( (++i) + (i+=32500 + (--i) ) - (++i) ); // i = 0 // 0 + ( (1) + (i+=32500 + (--i) ) - (++i) ); // i = 1 // 0 + ( (1) + (i+=32500 + (0) ) - (++i) ); // i = 0 // 0 + ( (1) + (32500 + (0) ) - (++i) ); // i = 32500 // 0 + ( (1) + (32500) - (++i) ); // i = 32500 // 0 + ( (1) + (32500) - (32501) ); // i = 32501 // 0 + ( 32501 - 32501 ); // i = 32501 // 0 // i = 0
Paranthesis优先。 顺序将从最内层到最外层
(i+=2 + --i) =>i=i+=2==(2) --2 =0 (++i - ++i) =>1-1=0 i=i+ =0+0 =0
每个expression式评估为0