执行此操作后(幕后)会发生什么?
int x = 7;
x = x++;
也就是说,何时在一个语句中对变量进行后递增并分配给自己?我编译并执行了这个。即使整个陈述之后x
仍然是7 。在我的书中,它说是递增的!x
x += 1
,除非可能是循环的。for(int x=0; x<7; x++)
执行此操作后(幕后)会发生什么?
int x = 7;
x = x++;
也就是说,何时在一个语句中对变量进行后递增并分配给自己?我编译并执行了这个。即使整个陈述之后x
仍然是7 。在我的书中,它说是递增的!x
x += 1
,除非可能是循环的。for(int x=0; x<7; x++)
Answers:
x
确实增加了。但是,您正在将x
back 的旧值分配给它自己。
x = x++;
x++
递增x
并返回其旧值。x =
将旧值分配回自己。因此,最后x
将其分配回其初始值。
x = x++;
相当于
int tmp = x;
x++;
x = tmp;
x=x+1
而不是x++
x = x++
,而不仅仅是发布增量x++
。
x = ++x;
等同于int tmp = x; ++x; x = tmp;
,因此我们可以通过什么逻辑推断出您的答案正确(正确)?
x=x++
=MOV x,tmp; INC x; MOV tmp,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.
简而言之,该声明无效。
重点:
后缀递增/递减表达式的值是递增/递减发生之前的操作数的值。(对于“前缀”格式,该值为操作后的操作数的值,)
在将值分配给LHS 之前,已对赋值表达式的RHS进行了完全评估(包括任何增量,减量和/或其他副作用)。
请注意,与C和C ++不同,Java中表达式的求值顺序是完全指定的,并且没有平台特定变体的空间。从当前线程的角度来看,只有在编译器不能改变执行代码的结果的情况下,编译器才可以对其进行重新排序。在这种情况下,将允许编译器优化整个语句,因为可以证明它是无操作的。
如果还不是很明显:
希望像FindBugs和PMD这样的代码检查器可以将这样的代码标记为可疑。
x++
而不是x = x++
。
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
,在增量之前(基本上意味着您的增量不执行任何操作),先进行推送(然后再分配)
在中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
情况2:
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
因为x ++在将值赋给变量之后会增加其值。以此类推,并在执行此行期间:
x++;
varialbe 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的值加1,然后在expression中使用。
因此,如果您这样做 x = ++x ; // where x = 7
,则将获得8的值。
为了更清楚,请尝试找出多少个printf语句将执行以下代码
while(i++ <5)
printf("%d" , ++i); // This might clear your concept upto great extend
x
是8,但它是7-读取和分配之间发生增量
所以这意味着:
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
非常依赖编译器!
(x = x + 1, x-1)
在C中一样,其中允许使用逗号分隔的表达式。
我认为无需编写代码也只需思考就可以解决这个争议。
考虑功能i ++和++ i,例如Func1&Func2。
现在我= 7;
Func1(i ++)返回7,Func2(++ i)返回8(每个人都知道这一点)。在内部,两个函数都将i增至8,但是它们返回不同的值。
因此,我= i ++调用了函数Func1。在函数内部,我递增到8,但完成后函数返回7。
因此最终将7分配给i。(所以最后,我= 7)
int x = 7; x = ++x;
,当然仍然是可怕的代码,您不需要重新分配。int x = 7; x++;
足够。