我试图深入了解post和pre incrementors,但我对以下表达式有点困惑:
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
}
我知道我在哪里错过了逻辑,但在哪里?
我尝试过的事情:
感谢您的帮助
PS:评论是我的微积分的细节
编辑1
我尝试将2
中的de hard编码值更改为其他内容,结果始终为0
看看这个例子:
int i = 0;
i = i+=(++i + (i+=32500 + --i) - ++i);
System.out.println(i); // Prints 0
这个表达式在逻辑上应该远离0
,但不知何故它会打印它。
当我使用否定时会发生同样的情况:
int i = 0;
i = i+=(++i + (i+=(-32650) + --i) - ++i);
System.out.println(i); // Prints 0
编辑2
现在,我将i
的值更改为:
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
每次都给出i
的两倍,无论硬编码值是什么。
答案 0 :(得分:22)
引用Java Language Specification, 15.7 Evaluation Order:
Java编程语言保证运算符的操作数似乎以特定的评估顺序进行评估,即从从左到右。
在评估右手操作数的任何部分之前,二元运算符的左侧操作数似乎完全评估。
如果运算符是复合赋值运算符(§15.26.2),则对左侧操作数的计算包括记住左侧操作数表示的变量和获取并保存该变量的值,以便在隐含的二进制操作中使用。
因此,基本上,i += ++i
会记住左侧i
的旧值,在评估右侧之前。
请记住,操作数的评估顺序和运算符的优先级是两回事。
逐步显示评估顺序,并在{braces}中保存值:
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;
答案 1 :(得分:5)
这是考虑到您的第一次编辑(使用未知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 operator所以它是右关联的:在片段中,我添加了括号来更清楚地表达这一点++
和postfix decrement operator --
从值中加1或减1,结果将存储回变量。+
additive operator首先计算左手操作数,然后计算右手操作数。进行第二次修改(添加了未知的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
}
答案 2 :(得分:2)
我建议如下:以不同方式格式化代码,以便每行只有1个语句,例如
@Test
public void test() {
int i = 0;
i =
i+=
(
++i
+
(
i+=
2
+
--i
)
-
++i
);
System.out.println(i); // Prints 0 instead of 5
}
然后在调试器下运行它并始终按F5(“Step into”)。这有助于您了解评估项目的顺序:
int i=0;
i=
:...(需要等待计算结果A)i+=
...(需要等待B)++i
:i = 1 i+=
...(需要等待C)2+
--i
:i = 0 -
++i
:i = 4且 - 的操作数也是4 第10行将始终生成第3行0
的结果,因此整个操作永远不会更改i的初始值。
答案 3 :(得分:1)
好的,让我们分解一切:
int i = 0; // i = 0, no big deal
然后开始进入最内在的括号:
(i+=2 + --i)
i
并使用结果(-1
)-1+2=1
)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:)
答案 4 :(得分:1)
由于优先级最高(...)将首先评估,然后++& - 然后是剩下的运营商。 你的表达就像
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
请完整地表达您的表达。您将理解表达式的评估顺序。
对于你的编辑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
答案 5 :(得分:1)
我追踪了i的值,结果如下:
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的值。
答案 6 :(得分:0)
Paranthesis优先。订单将从最内层到最外层
(i+=2 + --i) =>i=i+=2==(2) --2 =0
(++i - ++i) =>1-1=0
i=i+ =0+0 =0
每个表达式的计算结果为0