为什么它会进入无限循环?

时间:2022-08-30 08:45:06

I have the following code:

我有以下代码:

public class Tests {
    public static void main(String[] args) throws Exception {
        int x = 0;
        while(x<3) {
            x = x++;
            System.out.println(x);
        }
    }
}

We know he should have writen just x++ or x=x+1, but on x = x++ it should first attribute x to itself, and later increment it. Why does x continue with 0 as value?

我们知道他应该只写x++或x=x+1,但在x=x+ +上,它应该首先把x属性赋值给自己,然后再增加它。为什么x继续以0为值?

--update

- - -更新

Here's the bytecode:

字节码:

public class Tests extends java.lang.Object{
public Tests();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_3
   4:   if_icmpge   22
   7:   iload_1
   8:   iinc    1, 1
   11:  istore_1
   12:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   15:  iload_1
   16:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   19:  goto    2
   22:  return

}

I'll read about the instructions to try to understand...

我将阅读有关说明,试图了解……

27 个解决方案

#1


346  

Note: Originally I posted C# code in this answer for purposes of illustration, since C# allows you to pass int parameters by reference with the ref keyword. I've decided to update it with actual legal Java code using the first MutableInt class I found on Google to sort of approximate what ref does in C#. I can't really tell if that helps or hurts the answer. I will say that I personally haven't done all that much Java development; so for all I know there could be much more idiomatic ways to illustrate this point.

注意:最初,我在这个答案中发布了c#代码,用于说明,因为c#允许您通过引用ref关键字来传递int参数。我已经决定用我在谷歌上找到的第一个MutableInt类来对它进行更新,以近似于ref在c#中所做的工作。我不知道这是否有助于解决问题。我要说的是,我个人并没有做太多的Java开发;因此,我知道有更多的惯用方法来说明这一点。


Perhaps if we write out a method to do the equivalent of what x++ does it will make this clearer.

也许,如果我们写出一个方法来做与x++相同的方法,它会使这个更清楚。

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.

对吧?增加传递的值并返回原始值:这是后增量运算符的定义。

Now, let's see how this behavior plays out in your example code:

现在,让我们看看在您的示例代码中这种行为是如何发挥作用的:

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x) does what? Increments x, yes. And then returns what x was before the increment. This return value then gets assigned to x.

后增量(x)是什么?增加x,是的。然后返回x在增量之前的值。这个返回值被分配给x。

So the order of values assigned to x is 0, then 1, then 0.

所以赋给x的值的顺序是0,然后是1,然后是0。

This might be clearer still if we re-write the above:

如果我们重写上面的内容,可能会更清楚一些:

MutableInt x = new MutableInt();    // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp;                           // Now x is 0 again.

Your fixation on the fact that when you replace x on the left side of the above assignment with y, "you can see that it first increments x, and later attributes it to y" strikes me as confused. It is not x that is being assigned to y; it is the value formerly assigned to x. Really, injecting y makes things no different from the scenario above; we've simply got:

当你用y替换x的左边的时候,你会发现,“你可以看到它第一次增加x,然后把它归为y”让我感到困惑。不是x被赋给y;它是以前分配给x的值,实际上,注入y使情况与上面的情形没有什么不同;我们仅仅有:

MutableInt x = new MutableInt();    // x is 0.
MutableInt y = new MutableInt();    // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp;                           // y is still 0.

So it's clear: x = x++ effectively does not change the value of x. It always causes x to have the values x0, then x0 + 1, and then x0 again.

所以很明显,x = x++实际上并没有改变x的值,它总是导致x的值是x0,然后是x0 + 1,然后是x0。


Update: Incidentally, lest you doubt that x ever gets assigned to 1 "between" the increment operation and the assignment in the example above, I've thrown together a quick demo to illustrate that this intermediate value does indeed "exist," though it will never be "seen" on the executing thread.

更新:顺便说一下,为了避免您怀疑x在增量操作和上面的例子中的赋值之间被赋值为1,我已经抛出了一个快速的演示来说明这个中间值确实“存在”,尽管它在执行线程上永远不会被“看到”。

The demo calls x = x++; in a loop while a separate thread continuously prints the value of x to the console.

演示调用x = x++;在一个循环中,一个单独的线程继续将x的值输出到控制台。

public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
        LoopingThread t = new LoopingThread();
        System.out.println("Starting background thread...");
        t.start();

        while (true) {
            x = x++;
        }
    }
}

class LoopingThread extends Thread {
    public @Override void run() {
        while (true) {
            System.out.println(Main.x);
        }
    }
}

Below is an excerpt of the above program's output. Notice the irregular occurrence of both 1s and 0s.

下面是上述程序输出的摘录。注意1和0的不规则发生。

Starting background thread...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1

#2


167  

x = x++ works in the following way:

x = x++的工作方式如下:

  • First it evaluates expression x++. Evaluation of this expression produces an expression value (which is the value of x before increment) and increments x.
  • 首先,它计算表达式x++。这个表达式的评估产生一个表达式值(即x在增量之前的值)和增量x。
  • Later it assigns the expression value to x, overwriting incremented value.
  • 稍后,它将表达式值赋给x,重写递增值。

So, the sequence of events looks like follows (it's an actual decompiled bytecode, as produced by javap -c, with my comments):

因此,事件的顺序如下(它是由javap -c生成的实际的编译后的字节码,我的注释):

   8:   iload_1         // Remember current value of x in the stack
   9:   iinc    1, 1    // Increment x (doesn't change the stack)
   12:  istore_1        // Write remebered value from the stack to x

For comparison, x = ++x:

为了比较,x = +x:

   8:   iinc    1, 1    // Increment x
   11:  iload_1         // Push value of x onto stack
   12:  istore_1        // Pop value from the stack to x

#3


104  

This happens because the value of x doesn't get incremented at all.

这是因为x的值不会增加。

x = x++;

is equivalent to

相当于

int temp = x;
x++;
x = temp;

Explanation:

解释:

Let's look at the byte code for this operation. Consider a sample class:

让我们看一下这个操作的字节码。考虑一个示例类:

class test {
    public static void main(String[] args) {
        int i=0;
        i=i++;
    }
}

Now running the class disassembler on this we get:

现在运行类反汇编器,我们得到:

$ javap -c test
Compiled from "test.java"
class test extends java.lang.Object{
test();
  Code:
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return

public static void main(java.lang.String[]);
  Code:
   0:    iconst_0
   1:    istore_1
   2:    iload_1
   3:    iinc    1, 1
   6:    istore_1
   7:    return
}

Now the Java VM is stack based which means for each operation, the data will be pushed onto the stack and from stack the data will popped out to perform the operation. There is also another data structure, typically an array to store the local variables. The local variables are given ids which are just the indexes to the array.

现在,Java VM是基于堆栈的,这意味着对于每个操作,数据将被推送到堆栈上,并且从堆栈中取出数据来执行操作。还有另一个数据结构,通常是一个存储本地变量的数组。局部变量的id是数组的索引。

Let us look at the mnemonics in main() method:

让我们来看看main()方法中的助记符:

  • iconst_0: The constant value 0 is pushed on to the stack.
  • iconst_0:常量值0被推送到堆栈上。
  • istore_1: The top element of the stack is popped out and stored in the local variable with index 1
    which is x.
  • istore_1:堆栈的顶部元素被弹出并存储在本地变量中,索引1为x。
  • iload_1 : The value at the location 1 that is value of x which is 0, is pushed into the stack.
  • iload_1:位置1的值,即x的值为0,被推入堆栈中。
  • iinc 1, 1 : The value at the memory location 1 is incremented by 1. So x now becomes 1.
  • iinc 1,1:内存位置1的值增加1。所以x变成1。
  • istore_1 : The value at the top of the stack is stored to the memory location 1. That is 0 is assigned to x overwriting its incremented value.
  • istore_1:堆栈顶部的值存储到内存位置1。这是0被赋给x重写它的递增值。

Hence the value of x does not change resulting in the infinite loop.

因此,x的值不会改变导致无限循环。

#4


52  

  1. Prefix notation will increment the variable BEFORE the expression is evaluated.
  2. 前缀表示法将在计算表达式之前增加变量。
  3. Postfix notation will increment AFTER the expression evaluation.
  4. 后缀表示法将在表达式求值后增加。

However "=" has a lower operator precedence than "++".

但是,“=”比“++”具有较低的运算符优先级。

So x=x++; should evaluate as follows

所以x = x + +;应该评估如下

  1. x prepared for assignment (evaluated)
  2. x准备分配(评估)
  3. x incremented
  4. x增加
  5. Previous value of x assigned to x.
  6. x的先前值。

#5


34  

None of the answers where quite spot on, so here goes:

没有一个答案是完全正确的,所以这里是:

When you're writing int x = x++, you're not assigning x to be itself at the new value, you're assigning x to be the return value of the x++ expression. Which happens to be the original value of x, as hinted in Colin Cochrane's answer .

当你写int x = x++时,你不是在赋值x在新的值上,而是赋值x为x++表达式的返回值。这恰好是x的原值,正如科林·科克伦的答案所暗示的那样。

For fun, test the following code:

为了好玩,测试以下代码:

public class Autoincrement {
        public static void main(String[] args) {
                int x = 0;
                System.out.println(x++);
                System.out.println(x);
        }
}

The result will be

结果将是

0
1

The return value of the expression is the initial value of x, which is zero. But later on, when reading the value of x, we receive the updated value , that is one.

表达式的返回值是x的初始值,也就是0。但之后,当读取x的值时,我们会得到更新后的值,即1。

#6


29  

It has been already explained well by other. I just include the links to the relevant Java specification sections.

它已经被其他的解释清楚了。我只是将链接添加到相关的Java规范部分。

x = x++ is an expression. Java will follow the evaluation order. It will first evaluate the expression x++, which will increment x and set result value to the previous value of x. Then it will assign the expression result to the variable x. At the end, x is back at its previous value.

x = x++是一个表达式。Java将遵循评估顺序。它将首先对表达式x++进行评估,它将增加x,并将结果值设置为x的前一个值,然后将表达式结果赋值给变量x,最后,x返回到原来的值。

#7


18  

This statement:

这句话:

x = x++;

evaluates like this:

评估如下:

  1. Push x onto the stack;
  2. 把x推到堆栈上;
  3. Increment x;
  4. 增加x;
  5. Pop x from the stack.
  6. 从堆栈中取出x。

So the value is unchanged. Compare that to:

所以这个值是不变的。对比:

x = ++x;

which evaluates as:

的评价:

  1. Increment x;
  2. 增加x;
  3. Push x onto the stack;
  4. 把x推到堆栈上;
  5. Pop x from the stack.
  6. 从堆栈中取出x。

What you want is:

你想要的是:

while (x < 3) {
  x++;
  System.out.println(x);
}

#8


10  

The answer is pretty straightforward. It has to do with the order things are evaluated. x++ returns the value x then increments x.

答案很简单。它和排序有关。x++返回值x,然后递增x。

Consequently, the value of the expression x++ is 0. So you are assigning x=0 each time in the loop. Certainly x++ increments this value, but that happens before the assignment.

因此,表达式x++的值为0。所以每次循环中都分配x=0。当然,x++会增加这个值,但是在赋值之前。

#9


8  

From http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

从http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

The increment/decrement operators can be applied before (prefix) or after (postfix) the operand. The code result++; and ++result; will both end in result being incremented by one. The only difference is that the prefix version (++result) evaluates to the incremented value, whereas the postfix version (result++) evaluates to the original value. If you are just performing a simple increment/decrement, it doesn't really matter which version you choose. But if you use this operator in part of a larger expression, the one that you choose may make a significant difference.

递增/递减运算符可应用于(前缀)或(后缀)操作数。+ +代码的结果;+ +的结果;这两种结果都将被1增加。唯一的区别是,前缀版本(++result)计算的是递增值,而后缀版本(result++)计算的是原始值。如果您只是执行一个简单的递增/递减,那么选择哪个版本并不重要。但是如果你在一个更大的表达式中使用这个运算符,你所选择的这个运算符可能会产生显著的不同。

To illustrate, try the following:

为了说明这一点,请尝试以下方法:

    int x = 0;
    int y = 0;
    y = x++;
    System.out.println(x);
    System.out.println(y);

Which will print 1 and 0.

它将输出1和0。

#10


7  

You're effectively getting the following behavior.

你实际上得到了以下行为。

  1. grab the value of x (which is 0) as "the result" of the right side
  2. 将x(即0)的值作为右侧的“结果”。
  3. increment the value of x (so x is now 1)
  4. 增加x的值(所以x现在是1)
  5. assign the result of the right side (which was saved as 0) to x (x is now 0)
  6. 将右侧(保存为0)的结果赋给x (x现在为0)

The idea being that the post-increment operator (x++) increments that variable in question AFTER returning its value for use in the equation it's used in.

这个想法是,后增量运算符(x++)在返回其值后,在返回值后增加该变量的值。

Edit: Adding a slight bit because of the comment. Consider it like the following.

编辑:添加一点,因为评论。考虑如下。

x = 1;        // x == 1
x = x++ * 5;
              // First, the right hand side of the equation is evaluated.
  ==>  x = 1 * 5;    
              // x == 2 at this point, as it "gave" the equation its value of 1
              // and then gets incremented by 1 to 2.
  ==>  x = 5;
              // And then that RightHandSide value is assigned to 
              // the LeftHandSide variable, leaving x with the value of 5.

#11


7  

You don't really need the machine code to understand what's happending.

你不需要机器代码来理解发生了什么。

According the definitions:

根据定义:

  1. The assignment operator evaluates the right-hand side expression, and stores it in a temporary variable.

    赋值运算符计算右侧表达式,并将其存储在一个临时变量中。

    1.1. The current value of x is copied into this temporary variable

    1.1。x的当前值被复制到这个临时变量中。

    1.2. x is incremented now.

    1.2。x是增加了。

  2. The temporary variable is then copied into the left-hand side of the expression, which is x by chance! So that's why the old value of x is again copied into itself.

    然后将临时变量复制到表达式的左边,这是x的机会!这就是为什么x的旧值再次被复制。

It is pretty simple.

这是非常简单的。

#12


5  

This is because it never gets incremented in this case. x++ will use the value of it first before incrementing like on this case it will be like:

这是因为在这种情况下它不会增加。x++会先用它的值,然后再递增,就像这样,它会是:

x = 0;

But if you do ++x; this will increase.

但如果是++x;这将会增加。

#13


3  

The value stays at 0 because the value of x++ is 0. In this case it doesn't matter if the value of x is increased or not, the assignment x=0 is executed. This will overwrite the temporary incremented value of x (which was 1 for a "very short time").

值保持在0,因为x++的值是0。在这种情况下,如果x的值是否增加了,赋值x=0将被执行。这将覆盖x的临时递增值(即“非常短的时间”)。

#14


1  

This works how you expect the other one to. It's the difference between prefix and postfix.

这是你对另一个人的期望。这就是前缀和后缀的区别。

int x = 0; 
while (x < 3)    x = (++x);

#15


1  

Think of x++ as a function call that "returns" what X was before the increment (that's why it's called a post-increment).

把x++看作一个函数调用,它“返回”x在增量之前的值(这就是为什么它被称为后增量)。

So the operation order is:
1: cache the value of x before incrementing
2: increment x
3: return the cached value (x before it was incremented)
4: return value is assigned to x

因此,操作顺序是:1:在递增2之前缓存x的值:增量x 3:返回缓存的值(在它被增加之前的x):返回值被赋值给x。

#16


1  

When the ++ is on the rhs, the result is returned before the number is incremented. Change to ++x and it would have been fine. Java would have optimised this to perform a single operation (the assignment of x to x) rather than the increment.

当++在rhs上时,结果在数字递增之前返回。改成++x就可以了。Java将优化此操作以执行单个操作(x到x的赋值),而不是增量。

#17


1  

Well as far as I can see, the error occurs, due to the assignment overriding the incremented value, with the value prior to incrementation, i.e. it undoes the increment.

在我看来,错误发生了,因为作业覆盖了递增的值,在增量之前的值,也就是说,它取消了增量。

Specifically, the "x++" expression, has the value of 'x' prior to increment as opposed to "++x" which has the value of 'x' after incrementation.

具体来说,“x++”表达式,在增量之前有“x”的值,而不是“++x”,它在增量之后有“x”的值。

If you are interested in investigating the bytecode, we will take a look at the three lines in question:

如果您有兴趣对字节码进行调查,我们将查看以下三行:

 7:   iload_1
 8:   iinc    1, 1
11:  istore_1

7: iload_1 # Will put the value of the 2nd local variable on the stack
8: iinc 1,1 # will increment the 2nd local variable with 1, note that it leaves the stack untouched!
9: istore_1 # Will pop the top of stack and save the value of this element to the 2nd local variable
(You can read the effects of each JVM instruction here)

7:iload_1 #将把第2个本地变量的值放在堆栈8:iinc 1,1 #将增加第2个本地变量的值1,注意它将保持堆栈不变!9:istore_1 #将弹出堆栈顶部并将该元素的值保存到第二个本地变量(您可以阅读这里的每个JVM指令的效果)

This is why the above code will loop indefinitely, whereas the version with ++x will not. The bytecode for ++x should look quite different, as far as I remember from the 1.3 Java compiler I wrote a little over a year ago, the bytecode should go something like this:

这就是上面的代码将无限循环的原因,而使用++x的版本则不会。关于++x的字节码应该看起来很不一样,我记得我在一年前写过的1.3 Java编译器中,字节码应该是这样的:

iinc 1,1
iload_1
istore_1

So just swapping the two first lines, changes the semantics so that the value left on the top of stack, after the increment (i.e. the 'value' of the expression) is the value after the increment.

因此,只需交换两个第一行,改变语义,使堆栈顶部的值(即表达式的“值”)在增量之后的值。

#18


1  

    x++
=: (x = x + 1) - 1

So:

所以:

   x = x++;
=> x = ((x = x + 1) - 1)
=> x = ((x + 1) - 1)
=> x = x; // Doesn't modify x!

Whereas

   ++x
=: x = x + 1

So:

所以:

   x = ++x;
=> x = (x = x + 1)
=> x = x + 1; // Increments x

Of course the end result is the same as just x++; or ++x; on a line by itself.

当然最终结果和x++一样;或+ + x;在一条直线上。

#19


1  

Sentence

句子

x = x++;

"translates" to

“翻译”

x = x;
x = x + 1;

That's it.

就是这样。

#20


0  

 x = x++; (increment is overriden by = )

because of above statement x never reaches 3;

因为上面的表述x从不到3;

#21


0  

I wonder if there's anything in the Java spec that precisely defines the behavior of this. (The obviously implication of that statement being that I'm too lazy to check.)

我想知道Java规范中是否有任何东西精确地定义了这个行为。(这句话显然暗示了我懒得去检查。)

Note from Tom's bytecode, the key lines are 7, 8 and 11. Line 7 loads x into the computation stack. Line 8 increments x. Line 11 stores the value from the stack back to x. In normal cases where you are not assigning values back to themselves, I don't think there would be any reason why you couldn't load, store, then increment. You would get the same result.

从Tom的字节码中可以看到,关键字是7、8和11。第7行将x加载到计算堆栈中。第8行递增x。第11行将堆栈的值从堆栈返回到x。在正常情况下,您没有为自己分配值,所以我不认为有任何原因导致您不能加载、存储、然后增加。结果是一样的。

Like, suppose you had a more normal case where you wrote something like: z=(x++)+(y++);

比如,假设你有一个更正常的情况你写的是:z=(x++)+(y++)

Whether it said (pseudocode to skip technicalities)

是否说(伪代码跳过技术细节)

load x
increment x
add y
increment y
store x+y to z

or

load x
add y
store x+y to z
increment x
increment y

should be irrelevant. Either implementation should be valid, I would think.

应该是无关紧要的。我认为,任何一个实现都应该是有效的。

I'd be extremely cautious about writing code that depends on this behavior. It looks very implementation-dependent, between-the-cracks-in-the-specs to me. The only time it would make a difference is if you did something crazy, like the example here, or if you had two threads running and were dependent on the order of evaluation within the expression.

我将非常谨慎地编写依赖于这种行为的代码。它看起来非常依赖于实现,对我来说是一种突破。唯一的区别是,如果你做了一些疯狂的事情,比如这里的例子,或者你有两个线程运行并且依赖于表达式中的评估顺序。

#22


0  

I think because in Java ++ has a higher precedence than = (assignment)...Does it? Look at http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html...

我认为,因为在Java ++中,优先级高于=(赋值)…不是吗?看看http://www.cs.uwf.edu/ ~ eelsheik / cop2253 /资源/ op_precedence.html……

The same way if you write x=x+1...+ has a higher precedence than = (assignment)

同样的方法,如果你写x=x+1…+的优先级高于=(赋值)

#23


0  

The x++ expression evaluates to x. The ++ part affect the value after the evaluation, not after the statement. so x = x++ is effectively translated into

x++表达式求值为x, ++部分影响评价后的值,而不是在语句之后。因此,x = x++被有效地转化为。

int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment

#24


0  

Before incrementing the value by one, the value is assigned to the variable.

在将值增加1之前,该值被赋给变量。

#25


0  

It's happening because it's post incremented. It means that the variable is incremented after the expression is evaluated.

它发生是因为它的位置增加了。这意味着在计算表达式之后,变量会递增。

int x = 9;
int y = x++;

x is now 10, but y is 9, the value of x before it was incremented.

x现在是10,但是y是9,x在增加之前的值。

See more in Definition of Post Increment.

查看更多关于Post增量的定义。

#26


0  

Check the below code,

检查下面的代码,

    int x=0;
    int temp=x++;
    System.out.println("temp = "+temp);
    x = temp;
    System.out.println("x = "+x);

the output will be,

输出,

temp = 0
x = 0

post increment means increment the value and return the value before the increment. That is why the value temp is 0. So what if temp = i and this is in a loop (except for the first line of code). just like in the question !!!!

post增量意味着在增量之前增加值并返回值。这就是为什么值temp是0。因此,如果temp = i和这是一个循环(除了第一行代码)。就像在问题中一样!!!!

#27


-1  

The increment operator is applied to the same variable as you are assigning to. That's asking for trouble. I am sure that you can see the value of your x variable while running this program.... that's should make it clear why the loop never ends.

增量运算符被应用到与您分配给的相同变量。这是自找麻烦。我相信你可以看到x变量的值在运行这个程序时....这就是为什么循环没有结束的原因。

#1


346  

Note: Originally I posted C# code in this answer for purposes of illustration, since C# allows you to pass int parameters by reference with the ref keyword. I've decided to update it with actual legal Java code using the first MutableInt class I found on Google to sort of approximate what ref does in C#. I can't really tell if that helps or hurts the answer. I will say that I personally haven't done all that much Java development; so for all I know there could be much more idiomatic ways to illustrate this point.

注意:最初,我在这个答案中发布了c#代码,用于说明,因为c#允许您通过引用ref关键字来传递int参数。我已经决定用我在谷歌上找到的第一个MutableInt类来对它进行更新,以近似于ref在c#中所做的工作。我不知道这是否有助于解决问题。我要说的是,我个人并没有做太多的Java开发;因此,我知道有更多的惯用方法来说明这一点。


Perhaps if we write out a method to do the equivalent of what x++ does it will make this clearer.

也许,如果我们写出一个方法来做与x++相同的方法,它会使这个更清楚。

public MutableInt postIncrement(MutableInt x) {
    int valueBeforeIncrement = x.intValue();
    x.add(1);
    return new MutableInt(valueBeforeIncrement);
}

Right? Increment the value passed and return the original value: that's the definition of the postincrement operator.

对吧?增加传递的值并返回原始值:这是后增量运算符的定义。

Now, let's see how this behavior plays out in your example code:

现在,让我们看看在您的示例代码中这种行为是如何发挥作用的:

MutableInt x = new MutableInt();
x = postIncrement(x);

postIncrement(x) does what? Increments x, yes. And then returns what x was before the increment. This return value then gets assigned to x.

后增量(x)是什么?增加x,是的。然后返回x在增量之前的值。这个返回值被分配给x。

So the order of values assigned to x is 0, then 1, then 0.

所以赋给x的值的顺序是0,然后是1,然后是0。

This might be clearer still if we re-write the above:

如果我们重写上面的内容,可能会更清楚一些:

MutableInt x = new MutableInt();    // x is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
x = temp;                           // Now x is 0 again.

Your fixation on the fact that when you replace x on the left side of the above assignment with y, "you can see that it first increments x, and later attributes it to y" strikes me as confused. It is not x that is being assigned to y; it is the value formerly assigned to x. Really, injecting y makes things no different from the scenario above; we've simply got:

当你用y替换x的左边的时候,你会发现,“你可以看到它第一次增加x,然后把它归为y”让我感到困惑。不是x被赋给y;它是以前分配给x的值,实际上,注入y使情况与上面的情形没有什么不同;我们仅仅有:

MutableInt x = new MutableInt();    // x is 0.
MutableInt y = new MutableInt();    // y is 0.
MutableInt temp = postIncrement(x); // Now x is 1, and temp is 0.
y = temp;                           // y is still 0.

So it's clear: x = x++ effectively does not change the value of x. It always causes x to have the values x0, then x0 + 1, and then x0 again.

所以很明显,x = x++实际上并没有改变x的值,它总是导致x的值是x0,然后是x0 + 1,然后是x0。


Update: Incidentally, lest you doubt that x ever gets assigned to 1 "between" the increment operation and the assignment in the example above, I've thrown together a quick demo to illustrate that this intermediate value does indeed "exist," though it will never be "seen" on the executing thread.

更新:顺便说一下,为了避免您怀疑x在增量操作和上面的例子中的赋值之间被赋值为1,我已经抛出了一个快速的演示来说明这个中间值确实“存在”,尽管它在执行线程上永远不会被“看到”。

The demo calls x = x++; in a loop while a separate thread continuously prints the value of x to the console.

演示调用x = x++;在一个循环中,一个单独的线程继续将x的值输出到控制台。

public class Main {
    public static volatile int x = 0;

    public static void main(String[] args) {
        LoopingThread t = new LoopingThread();
        System.out.println("Starting background thread...");
        t.start();

        while (true) {
            x = x++;
        }
    }
}

class LoopingThread extends Thread {
    public @Override void run() {
        while (true) {
            System.out.println(Main.x);
        }
    }
}

Below is an excerpt of the above program's output. Notice the irregular occurrence of both 1s and 0s.

下面是上述程序输出的摘录。注意1和0的不规则发生。

Starting background thread...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1

#2


167  

x = x++ works in the following way:

x = x++的工作方式如下:

  • First it evaluates expression x++. Evaluation of this expression produces an expression value (which is the value of x before increment) and increments x.
  • 首先,它计算表达式x++。这个表达式的评估产生一个表达式值(即x在增量之前的值)和增量x。
  • Later it assigns the expression value to x, overwriting incremented value.
  • 稍后,它将表达式值赋给x,重写递增值。

So, the sequence of events looks like follows (it's an actual decompiled bytecode, as produced by javap -c, with my comments):

因此,事件的顺序如下(它是由javap -c生成的实际的编译后的字节码,我的注释):

   8:   iload_1         // Remember current value of x in the stack
   9:   iinc    1, 1    // Increment x (doesn't change the stack)
   12:  istore_1        // Write remebered value from the stack to x

For comparison, x = ++x:

为了比较,x = +x:

   8:   iinc    1, 1    // Increment x
   11:  iload_1         // Push value of x onto stack
   12:  istore_1        // Pop value from the stack to x

#3


104  

This happens because the value of x doesn't get incremented at all.

这是因为x的值不会增加。

x = x++;

is equivalent to

相当于

int temp = x;
x++;
x = temp;

Explanation:

解释:

Let's look at the byte code for this operation. Consider a sample class:

让我们看一下这个操作的字节码。考虑一个示例类:

class test {
    public static void main(String[] args) {
        int i=0;
        i=i++;
    }
}

Now running the class disassembler on this we get:

现在运行类反汇编器,我们得到:

$ javap -c test
Compiled from "test.java"
class test extends java.lang.Object{
test();
  Code:
   0:    aload_0
   1:    invokespecial    #1; //Method java/lang/Object."<init>":()V
   4:    return

public static void main(java.lang.String[]);
  Code:
   0:    iconst_0
   1:    istore_1
   2:    iload_1
   3:    iinc    1, 1
   6:    istore_1
   7:    return
}

Now the Java VM is stack based which means for each operation, the data will be pushed onto the stack and from stack the data will popped out to perform the operation. There is also another data structure, typically an array to store the local variables. The local variables are given ids which are just the indexes to the array.

现在,Java VM是基于堆栈的,这意味着对于每个操作,数据将被推送到堆栈上,并且从堆栈中取出数据来执行操作。还有另一个数据结构,通常是一个存储本地变量的数组。局部变量的id是数组的索引。

Let us look at the mnemonics in main() method:

让我们来看看main()方法中的助记符:

  • iconst_0: The constant value 0 is pushed on to the stack.
  • iconst_0:常量值0被推送到堆栈上。
  • istore_1: The top element of the stack is popped out and stored in the local variable with index 1
    which is x.
  • istore_1:堆栈的顶部元素被弹出并存储在本地变量中,索引1为x。
  • iload_1 : The value at the location 1 that is value of x which is 0, is pushed into the stack.
  • iload_1:位置1的值,即x的值为0,被推入堆栈中。
  • iinc 1, 1 : The value at the memory location 1 is incremented by 1. So x now becomes 1.
  • iinc 1,1:内存位置1的值增加1。所以x变成1。
  • istore_1 : The value at the top of the stack is stored to the memory location 1. That is 0 is assigned to x overwriting its incremented value.
  • istore_1:堆栈顶部的值存储到内存位置1。这是0被赋给x重写它的递增值。

Hence the value of x does not change resulting in the infinite loop.

因此,x的值不会改变导致无限循环。

#4


52  

  1. Prefix notation will increment the variable BEFORE the expression is evaluated.
  2. 前缀表示法将在计算表达式之前增加变量。
  3. Postfix notation will increment AFTER the expression evaluation.
  4. 后缀表示法将在表达式求值后增加。

However "=" has a lower operator precedence than "++".

但是,“=”比“++”具有较低的运算符优先级。

So x=x++; should evaluate as follows

所以x = x + +;应该评估如下

  1. x prepared for assignment (evaluated)
  2. x准备分配(评估)
  3. x incremented
  4. x增加
  5. Previous value of x assigned to x.
  6. x的先前值。

#5


34  

None of the answers where quite spot on, so here goes:

没有一个答案是完全正确的,所以这里是:

When you're writing int x = x++, you're not assigning x to be itself at the new value, you're assigning x to be the return value of the x++ expression. Which happens to be the original value of x, as hinted in Colin Cochrane's answer .

当你写int x = x++时,你不是在赋值x在新的值上,而是赋值x为x++表达式的返回值。这恰好是x的原值,正如科林·科克伦的答案所暗示的那样。

For fun, test the following code:

为了好玩,测试以下代码:

public class Autoincrement {
        public static void main(String[] args) {
                int x = 0;
                System.out.println(x++);
                System.out.println(x);
        }
}

The result will be

结果将是

0
1

The return value of the expression is the initial value of x, which is zero. But later on, when reading the value of x, we receive the updated value , that is one.

表达式的返回值是x的初始值,也就是0。但之后,当读取x的值时,我们会得到更新后的值,即1。

#6


29  

It has been already explained well by other. I just include the links to the relevant Java specification sections.

它已经被其他的解释清楚了。我只是将链接添加到相关的Java规范部分。

x = x++ is an expression. Java will follow the evaluation order. It will first evaluate the expression x++, which will increment x and set result value to the previous value of x. Then it will assign the expression result to the variable x. At the end, x is back at its previous value.

x = x++是一个表达式。Java将遵循评估顺序。它将首先对表达式x++进行评估,它将增加x,并将结果值设置为x的前一个值,然后将表达式结果赋值给变量x,最后,x返回到原来的值。

#7


18  

This statement:

这句话:

x = x++;

evaluates like this:

评估如下:

  1. Push x onto the stack;
  2. 把x推到堆栈上;
  3. Increment x;
  4. 增加x;
  5. Pop x from the stack.
  6. 从堆栈中取出x。

So the value is unchanged. Compare that to:

所以这个值是不变的。对比:

x = ++x;

which evaluates as:

的评价:

  1. Increment x;
  2. 增加x;
  3. Push x onto the stack;
  4. 把x推到堆栈上;
  5. Pop x from the stack.
  6. 从堆栈中取出x。

What you want is:

你想要的是:

while (x < 3) {
  x++;
  System.out.println(x);
}

#8


10  

The answer is pretty straightforward. It has to do with the order things are evaluated. x++ returns the value x then increments x.

答案很简单。它和排序有关。x++返回值x,然后递增x。

Consequently, the value of the expression x++ is 0. So you are assigning x=0 each time in the loop. Certainly x++ increments this value, but that happens before the assignment.

因此,表达式x++的值为0。所以每次循环中都分配x=0。当然,x++会增加这个值,但是在赋值之前。

#9


8  

From http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

从http://download.oracle.com/javase/tutorial/java/nutsandbolts/op1.html

The increment/decrement operators can be applied before (prefix) or after (postfix) the operand. The code result++; and ++result; will both end in result being incremented by one. The only difference is that the prefix version (++result) evaluates to the incremented value, whereas the postfix version (result++) evaluates to the original value. If you are just performing a simple increment/decrement, it doesn't really matter which version you choose. But if you use this operator in part of a larger expression, the one that you choose may make a significant difference.

递增/递减运算符可应用于(前缀)或(后缀)操作数。+ +代码的结果;+ +的结果;这两种结果都将被1增加。唯一的区别是,前缀版本(++result)计算的是递增值,而后缀版本(result++)计算的是原始值。如果您只是执行一个简单的递增/递减,那么选择哪个版本并不重要。但是如果你在一个更大的表达式中使用这个运算符,你所选择的这个运算符可能会产生显著的不同。

To illustrate, try the following:

为了说明这一点,请尝试以下方法:

    int x = 0;
    int y = 0;
    y = x++;
    System.out.println(x);
    System.out.println(y);

Which will print 1 and 0.

它将输出1和0。

#10


7  

You're effectively getting the following behavior.

你实际上得到了以下行为。

  1. grab the value of x (which is 0) as "the result" of the right side
  2. 将x(即0)的值作为右侧的“结果”。
  3. increment the value of x (so x is now 1)
  4. 增加x的值(所以x现在是1)
  5. assign the result of the right side (which was saved as 0) to x (x is now 0)
  6. 将右侧(保存为0)的结果赋给x (x现在为0)

The idea being that the post-increment operator (x++) increments that variable in question AFTER returning its value for use in the equation it's used in.

这个想法是,后增量运算符(x++)在返回其值后,在返回值后增加该变量的值。

Edit: Adding a slight bit because of the comment. Consider it like the following.

编辑:添加一点,因为评论。考虑如下。

x = 1;        // x == 1
x = x++ * 5;
              // First, the right hand side of the equation is evaluated.
  ==>  x = 1 * 5;    
              // x == 2 at this point, as it "gave" the equation its value of 1
              // and then gets incremented by 1 to 2.
  ==>  x = 5;
              // And then that RightHandSide value is assigned to 
              // the LeftHandSide variable, leaving x with the value of 5.

#11


7  

You don't really need the machine code to understand what's happending.

你不需要机器代码来理解发生了什么。

According the definitions:

根据定义:

  1. The assignment operator evaluates the right-hand side expression, and stores it in a temporary variable.

    赋值运算符计算右侧表达式,并将其存储在一个临时变量中。

    1.1. The current value of x is copied into this temporary variable

    1.1。x的当前值被复制到这个临时变量中。

    1.2. x is incremented now.

    1.2。x是增加了。

  2. The temporary variable is then copied into the left-hand side of the expression, which is x by chance! So that's why the old value of x is again copied into itself.

    然后将临时变量复制到表达式的左边,这是x的机会!这就是为什么x的旧值再次被复制。

It is pretty simple.

这是非常简单的。

#12


5  

This is because it never gets incremented in this case. x++ will use the value of it first before incrementing like on this case it will be like:

这是因为在这种情况下它不会增加。x++会先用它的值,然后再递增,就像这样,它会是:

x = 0;

But if you do ++x; this will increase.

但如果是++x;这将会增加。

#13


3  

The value stays at 0 because the value of x++ is 0. In this case it doesn't matter if the value of x is increased or not, the assignment x=0 is executed. This will overwrite the temporary incremented value of x (which was 1 for a "very short time").

值保持在0,因为x++的值是0。在这种情况下,如果x的值是否增加了,赋值x=0将被执行。这将覆盖x的临时递增值(即“非常短的时间”)。

#14


1  

This works how you expect the other one to. It's the difference between prefix and postfix.

这是你对另一个人的期望。这就是前缀和后缀的区别。

int x = 0; 
while (x < 3)    x = (++x);

#15


1  

Think of x++ as a function call that "returns" what X was before the increment (that's why it's called a post-increment).

把x++看作一个函数调用,它“返回”x在增量之前的值(这就是为什么它被称为后增量)。

So the operation order is:
1: cache the value of x before incrementing
2: increment x
3: return the cached value (x before it was incremented)
4: return value is assigned to x

因此,操作顺序是:1:在递增2之前缓存x的值:增量x 3:返回缓存的值(在它被增加之前的x):返回值被赋值给x。

#16


1  

When the ++ is on the rhs, the result is returned before the number is incremented. Change to ++x and it would have been fine. Java would have optimised this to perform a single operation (the assignment of x to x) rather than the increment.

当++在rhs上时,结果在数字递增之前返回。改成++x就可以了。Java将优化此操作以执行单个操作(x到x的赋值),而不是增量。

#17


1  

Well as far as I can see, the error occurs, due to the assignment overriding the incremented value, with the value prior to incrementation, i.e. it undoes the increment.

在我看来,错误发生了,因为作业覆盖了递增的值,在增量之前的值,也就是说,它取消了增量。

Specifically, the "x++" expression, has the value of 'x' prior to increment as opposed to "++x" which has the value of 'x' after incrementation.

具体来说,“x++”表达式,在增量之前有“x”的值,而不是“++x”,它在增量之后有“x”的值。

If you are interested in investigating the bytecode, we will take a look at the three lines in question:

如果您有兴趣对字节码进行调查,我们将查看以下三行:

 7:   iload_1
 8:   iinc    1, 1
11:  istore_1

7: iload_1 # Will put the value of the 2nd local variable on the stack
8: iinc 1,1 # will increment the 2nd local variable with 1, note that it leaves the stack untouched!
9: istore_1 # Will pop the top of stack and save the value of this element to the 2nd local variable
(You can read the effects of each JVM instruction here)

7:iload_1 #将把第2个本地变量的值放在堆栈8:iinc 1,1 #将增加第2个本地变量的值1,注意它将保持堆栈不变!9:istore_1 #将弹出堆栈顶部并将该元素的值保存到第二个本地变量(您可以阅读这里的每个JVM指令的效果)

This is why the above code will loop indefinitely, whereas the version with ++x will not. The bytecode for ++x should look quite different, as far as I remember from the 1.3 Java compiler I wrote a little over a year ago, the bytecode should go something like this:

这就是上面的代码将无限循环的原因,而使用++x的版本则不会。关于++x的字节码应该看起来很不一样,我记得我在一年前写过的1.3 Java编译器中,字节码应该是这样的:

iinc 1,1
iload_1
istore_1

So just swapping the two first lines, changes the semantics so that the value left on the top of stack, after the increment (i.e. the 'value' of the expression) is the value after the increment.

因此,只需交换两个第一行,改变语义,使堆栈顶部的值(即表达式的“值”)在增量之后的值。

#18


1  

    x++
=: (x = x + 1) - 1

So:

所以:

   x = x++;
=> x = ((x = x + 1) - 1)
=> x = ((x + 1) - 1)
=> x = x; // Doesn't modify x!

Whereas

   ++x
=: x = x + 1

So:

所以:

   x = ++x;
=> x = (x = x + 1)
=> x = x + 1; // Increments x

Of course the end result is the same as just x++; or ++x; on a line by itself.

当然最终结果和x++一样;或+ + x;在一条直线上。

#19


1  

Sentence

句子

x = x++;

"translates" to

“翻译”

x = x;
x = x + 1;

That's it.

就是这样。

#20


0  

 x = x++; (increment is overriden by = )

because of above statement x never reaches 3;

因为上面的表述x从不到3;

#21


0  

I wonder if there's anything in the Java spec that precisely defines the behavior of this. (The obviously implication of that statement being that I'm too lazy to check.)

我想知道Java规范中是否有任何东西精确地定义了这个行为。(这句话显然暗示了我懒得去检查。)

Note from Tom's bytecode, the key lines are 7, 8 and 11. Line 7 loads x into the computation stack. Line 8 increments x. Line 11 stores the value from the stack back to x. In normal cases where you are not assigning values back to themselves, I don't think there would be any reason why you couldn't load, store, then increment. You would get the same result.

从Tom的字节码中可以看到,关键字是7、8和11。第7行将x加载到计算堆栈中。第8行递增x。第11行将堆栈的值从堆栈返回到x。在正常情况下,您没有为自己分配值,所以我不认为有任何原因导致您不能加载、存储、然后增加。结果是一样的。

Like, suppose you had a more normal case where you wrote something like: z=(x++)+(y++);

比如,假设你有一个更正常的情况你写的是:z=(x++)+(y++)

Whether it said (pseudocode to skip technicalities)

是否说(伪代码跳过技术细节)

load x
increment x
add y
increment y
store x+y to z

or

load x
add y
store x+y to z
increment x
increment y

should be irrelevant. Either implementation should be valid, I would think.

应该是无关紧要的。我认为,任何一个实现都应该是有效的。

I'd be extremely cautious about writing code that depends on this behavior. It looks very implementation-dependent, between-the-cracks-in-the-specs to me. The only time it would make a difference is if you did something crazy, like the example here, or if you had two threads running and were dependent on the order of evaluation within the expression.

我将非常谨慎地编写依赖于这种行为的代码。它看起来非常依赖于实现,对我来说是一种突破。唯一的区别是,如果你做了一些疯狂的事情,比如这里的例子,或者你有两个线程运行并且依赖于表达式中的评估顺序。

#22


0  

I think because in Java ++ has a higher precedence than = (assignment)...Does it? Look at http://www.cs.uwf.edu/~eelsheik/cop2253/resources/op_precedence.html...

我认为,因为在Java ++中,优先级高于=(赋值)…不是吗?看看http://www.cs.uwf.edu/ ~ eelsheik / cop2253 /资源/ op_precedence.html……

The same way if you write x=x+1...+ has a higher precedence than = (assignment)

同样的方法,如果你写x=x+1…+的优先级高于=(赋值)

#23


0  

The x++ expression evaluates to x. The ++ part affect the value after the evaluation, not after the statement. so x = x++ is effectively translated into

x++表达式求值为x, ++部分影响评价后的值,而不是在语句之后。因此,x = x++被有效地转化为。

int y = x; // evaluation
x = x + 1; // increment part
x = y; // assignment

#24


0  

Before incrementing the value by one, the value is assigned to the variable.

在将值增加1之前,该值被赋给变量。

#25


0  

It's happening because it's post incremented. It means that the variable is incremented after the expression is evaluated.

它发生是因为它的位置增加了。这意味着在计算表达式之后,变量会递增。

int x = 9;
int y = x++;

x is now 10, but y is 9, the value of x before it was incremented.

x现在是10,但是y是9,x在增加之前的值。

See more in Definition of Post Increment.

查看更多关于Post增量的定义。

#26


0  

Check the below code,

检查下面的代码,

    int x=0;
    int temp=x++;
    System.out.println("temp = "+temp);
    x = temp;
    System.out.println("x = "+x);

the output will be,

输出,

temp = 0
x = 0

post increment means increment the value and return the value before the increment. That is why the value temp is 0. So what if temp = i and this is in a loop (except for the first line of code). just like in the question !!!!

post增量意味着在增量之前增加值并返回值。这就是为什么值temp是0。因此,如果temp = i和这是一个循环(除了第一行代码)。就像在问题中一样!!!!

#27


-1  

The increment operator is applied to the same variable as you are assigning to. That's asking for trouble. I am sure that you can see the value of your x variable while running this program.... that's should make it clear why the loop never ends.

增量运算符被应用到与您分配给的相同变量。这是自找麻烦。我相信你可以看到x变量的值在运行这个程序时....这就是为什么循环没有结束的原因。