执行此操作时(幕后)会发生什么?
int x = 7;
x = x++;
也就是说,当一个变量在一个语句中后递增并分配给它自己时?我编译并执行了这个。即使在整个语句之后x
仍然是 7 。在我的书中,它说这是递增的!x
执行此操作时(幕后)会发生什么?
int x = 7;
x = x++;
也就是说,当一个变量在一个语句中后递增并分配给它自己时?我编译并执行了这个。即使在整个语句之后x
仍然是 7 。在我的书中,它说这是递增的!x
x = x++;
相当于
int tmp = x;
x++;
x = tmp;
x
确实增加了。但是您正在将旧值分配x
回自身。
x = x++;
x++
递增x
并返回其旧值。x =
将旧值分配回自身。所以最后,x
被分配回它的初始值。
该声明:
x = x++;
相当于:
tmp = x; // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
// happens after the value is captured.
x = tmp; // ... this is the effect of assignment operation which is
// (unfortunately) clobbering the incremented value.
简而言之,该声明没有任何效果。
要点:
后缀增量/减量表达式的值是在增量/减量发生之前操作数的值。(在Prefix形式的情况下,该值是操作后的操作数的值,)
在将值分配给 LHS之前,赋值表达式的 RHS 会被完全评估(包括任何增量、减量和/或其他副作用) 。
请注意,与 C 和 C++ 不同,Java 中表达式的求值顺序是完全指定的,没有平台特定变化的空间。只有在不改变从当前线程的角度执行代码的结果的情况下,编译器才被允许重新排序操作。在这种情况下,允许编译器优化整个语句,因为可以证明它是空操作。
如果还不是很明显:
希望像 FindBugs 和 PMD 这样的代码检查器会将此类代码标记为可疑代码。
int x = 7;
x = x++;
它在 C 中具有未定义的行为,对于 Java,请参阅此答案。这取决于编译器会发生什么。
像这样的结构x = x++;
表明您可能误解了++
运算符的作用:
// original code
int x = 7;
x = x++;
让我们根据删除++
运算符重写它来做同样的事情:
// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7
现在,让我们重写它来做(我认为)你想要的:
// original code
int x = 7;
x++;
这里的微妙之处在于,++
运算符修改了变量x
,与诸如 之类的表达式不同x + x
,后者的计算结果为 int 值,但变量x
本身保持不变。考虑一个像古老for
循环这样的结构:
for(int i = 0; i < 10; i++)
{
System.out.println(i);
}
注意到里面了i++
吗?是同一个运营商。我们可以像这样重写这个for
循环,它的行为是一样的:
for(int i = 0; i < 10; i = i + 1)
{
System.out.println(i);
}
我还建议不要++
在大多数情况下在较大的表达式中使用运算符。由于它在前后增量(分别为和)中修改原始变量时的微妙之处,很容易引入难以追踪的细微错误。++x
x++
根据类文件得到的字节码,
两个分配都增加 x,但不同的是时间when the value is pushed onto the stack
在Case1
中,Push 在增量之前发生(然后分配)(本质上意味着您的增量什么都不做)
在Case2
中,首先发生增量(使其变为 8),然后压入堆栈(然后分配给 x)
情况1:
int x=7;
x=x++;
字节码:
0 bipush 7 //Push 7 onto stack
2 istore_1 [x] //Pop 7 and store in x
3 iload_1 [x] //Push 7 onto stack
4 iinc 1 1 [x] //Increment x by 1 (x=8)
7 istore_1 [x] //Pop 7 and store in x
8 return //x now has 7
案例二:
int x=7;
x=++x;
字节码
0 bipush 7 //Push 7 onto stack
2 istore_1 [x] //Pop 7 and store in x
3 iinc 1 1 [x] //Increment x by 1 (x=8)
6 iload_1 [x] //Push x onto stack
7 istore_1 [x] //Pop 8 and store in x
8 return //x now has 8
Post Increment 运算符的工作原理如下:
所以声明
int x = 7;
x = x++;
将被评估如下:
所以 x 确实增加了,但是由于 x++ 将结果分配回 x ,所以 x 的值被覆盖为其先前的值。
它在“”之后递增x = x++;
。如果你做了“ x = ++x;
”,那将是8。
递增发生在调用 x 之后,因此 x 仍然等于 7。调用 x 时 ++x 将等于 8
当你重新分配它的值时,x
它仍然是 7。尝试x = ++x
,你会得到 8 else do
x++; // don't re-assign, just increment
System.out.println(x); // prints 8
因为 x++ 在将其分配给变量之后会增加值。依此类推,在执行此行期间:
x++;
变量 x 仍将具有原始值 (7),但在另一行再次使用 x,例如
System.out.println(x + "");
会给你8。
如果要在赋值语句中使用递增的 x 值,请使用
++x;
这将使 x 增加 1,然后将该值分配给变量 x。
[编辑] 而不是 x = x++,它只是 x++;前者将 x 的原始值分配给它自己,所以它实际上在那条线上什么都不做。
什么时候发生int x = 7; x = x++;
?
ans -> x++
表示首先使用 x 的值作为表达式,然后将其增加 1。
这就是您的情况。将 RHS 上的 x 值复制到 LHS 上的变量 x 中,然后将 的值x
增加 1。
同样++x
意味着 ->
先将 x 的值加一,然后在表达式中使用。
因此,在您的情况下,如果您这样做, x = ++x ; // where x = 7
您将获得 8 的值。
为了更清楚起见,尝试找出有多少 printf 语句将执行以下代码
while(i++ <5)
printf("%d" , ++i); // This might clear your concept upto great extend
++x
is pre-increment ->
x在使用前
x++
递增is post-increment ->
x在使用后递增
int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented
所以这意味着:
x++
不等于x = x+1
因为:
int x = 7; x = x++;
x is 7
int x = 7; x = x = x+1;
x is 8
现在看起来有点奇怪:
int x = 7; x = x+=1;
x is 8
非常依赖编译器!
我认为这个争议可以在不进入代码和思考的情况下解决。
将 i++ 和 ++i 视为函数,例如 Func1 和 Func2。
现在 i=7;
Func1(i++) 返回 7,Func2(++i) 返回 8(每个人都知道这一点)。在内部,这两个函数都将 i 增加到 8 ,但它们返回不同的值。
所以 i = i++ 调用函数 Func1。在函数内部 i 递增到 8,但在完成时函数返回 7。
所以最终 7 被分配给 i。(所以最后,i = 7)
x = x++;
这是后增量运算符。应该理解为“使用操作数的值,然后递增操作数”。
如果您希望相反的情况发生,即“递增操作数,然后使用操作数的值”,则必须使用预递增运算符,如下所示。
x = ++x;
此运算符首先将 x 的值增加 1,然后将值分配回 x。
这是因为您使用了后增量运算符。在以下代码行中
x = x++;
发生的情况是,您将 x 的值分配给 x。在将 x 的值分配给 x 之后,x++ 递增 x。这就是后增量运算符的工作方式。它们在语句执行后工作。因此,在您的代码中,x 先返回,然后再递增。
如果你做了
x = ++x;
答案是 8,因为您使用了预增量运算符。这会在返回 x 的值之前先增加值。