我有以下代码:

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

我们知道他应该只写x++或x=x+1,但在x=x+ +时,它应该先把x归为自己,然后再加1。为什么x的值是0 ?

- - -更新

下面是字节码:

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

}

我会仔细阅读说明,试着理解……


当前回答

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

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

其他回答

这句话:

x = x++;

计算如下:

将x推入堆栈; 增加x; 从堆栈中取出x。

所以这个值是不变的。将其与:

x = ++x;

计算结果为:

增加x; 将x推入堆栈; 从堆栈中取出x。

你想要的是:

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

当++在rhs上时,在数字增加之前返回结果。 更改为++x就可以了。 Java会将其优化为执行单个操作(将x赋值给x),而不是增量操作。

我想知道Java规范中是否有精确定义此行为的内容。(这句话的明显意思是我懒得去检查。)

注意Tom的字节码,关键行是7、8和11。第7行将x加载到计算堆栈中。第8行增加x。第11行将堆栈的值存储回x。在正常情况下,如果你不将值赋值回自身,我不认为有任何理由不能加载,存储,然后增加。你会得到同样的结果。

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

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

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

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

我会非常谨慎地编写依赖于这种行为的代码。对我来说,它看起来非常依赖于实现。只有当您做了一些疯狂的事情(比如这里的例子),或者您有两个线程正在运行,并且依赖于表达式中的求值顺序时,才会产生影响。

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

根据定义:

赋值操作符求右边表达式的值,并将其存储在临时变量中。 1.1. x的当前值被复制到这个临时变量中 1.2. X现在是递增的。 然后将临时变量复制到表达式的左侧,也就是x !这就是为什么原来的x值又被复制到自身。

这很简单。

你有效地得到了以下行为。

获取x的值(它是0)作为右边的“结果” 增加x的值(x现在是1) 将右边的结果(保存为0)分配给x (x现在是0)

其思想是,后增量操作符(x++)在返回变量的值后对该变量进行增量,以便在使用该变量的方程中使用。

编辑:由于评论的原因,稍微增加了一点。像下面这样考虑。

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.