// 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,但不同的是 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
案例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
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.
什么时候会发生 int x = 7; x = x++; ? 答案-> x++ 表示首先使用x的值作为表达式,然后将其增加1。 你的情况就是这样。rhs上的x值被复制到lhs上的变量x,然后 x 增加1。 同样地 ++x 手段 -> 先将x的值增加1,然后在表达式中使用。 如果你这样做了 x = ++x ; // where x = 7 你将得到值8。 为了更清楚,请尝试找出有多少printf语句将执行以下代码
while(i++ <5)
printf("%d" , ++i); // This might clear your concept upto great extend
17条答案
按热度按时间vlf7wbxs1#
后增量运算符的工作方式如下:
存储操作数的上一个值。
递增操作数的值。
返回操作数的上一个值。
所以声明
评估如下:
x用值7初始化
后增量运算符存储x的前一个值,即返回7。
增加x,所以现在x是8
返回x的前一个值,即7,并将其赋值回x,因此x再次变为7
所以x确实增加了,但由于x++将结果赋值回x,所以x的值被重写为它以前的值。
q1qsirdb2#
递增发生在调用x之后,因此x仍然等于7++当x被调用时,x等于8
4ktjp1zp3#
x
不会递增。但你是在给x
回到它自己。uxhixvfz4#
像这样的构造
x = x++;
表明你可能误解了++
操作员:让我们重写它来做同样的事情,基于删除
++
操作员:现在,让我们重写它来做(我认为)你想要的:
这里的微妙之处在于
++
运算符修改变量x
,与表达式不同,例如x + x
,它将计算为int值,但保留变量x
它本身没有改变。想想像尊者这样的建筑for
回路:注意
i++
在那里?是同一个操作员。我们可以重写这个for
像这样循环,它的行为是一样的:我还建议不要使用
++
在大多数情况下,在较大的表达式中使用运算符。因为它在增量前后修改原始变量时的微妙之处(++x
以及x++
,很容易引入难以追踪的细微缺陷。g0czyy6m5#
它在c语言中有未定义的行为,对于java来说,可以看到这个答案。这取决于发生了什么。
jm81lzqq6#
这是因为您使用了后增量运算符。在下面的代码行中
结果是,你把x的值赋给x。x++将x的值赋给x后,x递增x。这就是后增量运算符的工作方式。它们在语句执行后工作。所以在代码中,x先返回,然后再递增。
如果你这么做了
答案是8,因为您使用了pre-increment操作符。这将在返回x的值之前先递增该值。
du7egjpx7#
所以这意味着:
x++
不等于x = x+1
因为:现在看来有点奇怪:
非常依赖编译器!
5hcedyr08#
我认为这场争论不需要进入代码就可以解决&只需思考。
把i++&i看作函数,比如func1&func2。
现在i=7;
func1(i)返回7,func2(i)返回8(大家都知道这一点)。在内部,这两个函数都将i增加到8,但它们返回不同的值。
所以i=i调用函数func1。在函数内部,i递增到8,但函数完成时返回7。
所以最终7被分配给i(最后,i=7)
daolsyd09#
根据从类文件中获取的字节码,
两个赋值都增加x,但不同的是
when the value is pushed onto the stack
在Case1
,push在增量之前发生(然后分配)(本质上意味着增量什么也不做)在
Case2
,增量首先发生(使其为8),然后推送到堆栈上(然后分配给x)案例1:
字节码:
案例2:
字节码
这里的堆栈是指操作数堆栈,本地:x索引:1类型:int
omvjsjqw10#
声明:
相当于:
简言之,该声明没有任何效力。
关键点:
后缀递增/递减表达式的值是递增/递减发生之前操作数的值(对于前缀形式,该值是运算后的操作数的值,)
赋值表达式的rhs在赋值给lhs之前被完全求值(包括任何增量、减量和/或其他副作用)。
请注意,与c和c不同,java中表达式的求值顺序是完全指定的,没有平台特定变化的空间。只有在不改变当前线程执行代码的结果的情况下,编译器才允许对操作重新排序。在这种情况下,编译器将被允许优化掉整个语句,因为可以证明它是禁止操作的。
如果还不明显:
“x=x;”几乎可以肯定在任何程序中都是错误的。
op(针对原始问题!)可能是“x++;”而不是“x=x++;”。
在同一个变量上结合自动递增/递减和赋值的语句很难理解,因此无论其正确性如何,都应避免使用。根本不需要编写这样的代码。
希望像findbugs和pmd这样的代码检查器能将这样的代码标记为可疑代码。
ni65a41a11#
什么时候会发生
int x = 7; x = x++;
?答案->
x++
表示首先使用x的值作为表达式,然后将其增加1。你的情况就是这样。rhs上的x值被复制到lhs上的变量x,然后
x
增加1。同样地
++x
手段->
先将x的值增加1,然后在表达式中使用。如果你这样做了
x = ++x ; // where x = 7
你将得到值8。为了更清楚,请尝试找出有多少printf语句将执行以下代码
wvmv3b1j12#
“之后递增”
x = x++;
". 如果你这样做的话,那就是8”x = ++x;
".juud5qan13#
++x
是预增量->
x在使用前递增x++
是后增量->
x在使用后递增inkz8wg914#
相当于
h6my8fg215#
因为x++在赋值给变量后会增加值。在执行这一行的过程中:
变量x仍将具有原始值(7),但在另一行上再次使用x,例如
我给你8英镑。
如果要在赋值语句中使用递增的x值,请使用
这将使x增加1,然后将该值赋给变量x。
[编辑]不是x=x++,而是x++;前者将x的原始值赋给它自己,所以它实际上在这条线上什么也不做。