【问题标题】:What is x after "x = x++"?“x = x++”之后的 x 是什么?
【发布时间】:2012-08-15 13:09:15
【问题描述】:

执行此操作时(幕后)会发生什么?

int x = 7;
x = x++;

也就是说,当一个变量在一个语句中后递增并分配给它自己时?我编译并执行了这个。 x 仍然是 7 即使在整个语句之后。在我的书中,它说x 增加了!

【问题讨论】:

  • 试试这个:int x = 7; x = ++x;,当然还是很糟糕的代码,你不需要重新分配。 int x = 7; x++; 就够了。
  • 这是一个非常糟糕的做法,不要在使用它的同一行中增加变量。
  • 我更喜欢使用x += 1,除非可能在循环中。 for(int x=0; x<7; x++)
  • @andyortlieb 没有对象,只是一个基本值。

标签: java operators post-increment


【解决方案1】:
x = x++;

等价于

int tmp = x;
x++;
x = tmp;

【讨论】:

  • 大声笑,递归定义。你可能应该使用x=x+1 而不是x++
  • @user606723:不。我的意思是整个声明x = x++,而不仅仅是帖子增量x++
  • 如果没有进一步的解释,我认为这不是那么有用。例如,x = ++x; 不等于int tmp = x; ++x; x = tmp;,那么根据什么逻辑我们可以推断出你的答案是正确的(它是正确的)?
  • 更清楚的是它在 asm x=x++ = MOV x,tmp; INC x; MOV tmp,x
  • @forker:我认为如果您使用适用于 Michael 正在使用的处理器的汇编指令会更清楚 ;)
【解决方案2】:

x 确实会增加。但是您将 x 的旧值分配回自身。


x = x++;
  1. x++ 递增 x 并返回其旧值。
  2. x = 将旧值分配回自身。

所以最后,x 被分配回其初始值。

【讨论】:

  • 那么,关于x = ++x;你会说什么
  • @HishamMuneer x 在这种情况下被读取之前首先递增,所以你最终得到x + 1
  • @HishamMuneer 为时已晚。但我把它放在这里是因为它可能对其他一些将来会关注的人有所帮助。理解这个问题的最好方法是查看为 x=x++ 和 x=++x 创建的汇编代码。另请参阅 Thinkingcap 的答案。
  • 我知道这是超级旧的,但我有一个问题。上面的操作顺序是否有标准保证?是否有可能在增量之前执行分配?
  • @EmeraldWeapon 它是用 Java 定义的。只有在 C/C++ 中才能看到这种恶作剧。
【解决方案3】:

声明:

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形式的情况下,该值是操作数操作之后的值,)

  • 赋值表达式的 RHS 被完全评估(包括任何增量、减量和/或其他副作用)值被赋给 LHS。

请注意,与 C 和 C++ 不同,Java 中表达式的求值顺序是完全指定的,没有平台特定变化的空间。只有在不改变从当前线程的角度执行代码的结果的情况下,编译器才被允许重新排序操作。在这种情况下,允许编译器优化整个语句,因为可以证明它是空操作。


如果还不是很明显:

  • "x = x++;"几乎可以肯定在任何程序中都是一个错误。
  • OP(对于原始问题!)可能意味着“x++;”而不是“x = x++;”。
  • 将自动递增/递减和对同一变量赋值的语句很难理解,因此应避免无论其正确性如何。根本不需要编写这样的代码。

希望 FindBugs 和 PMD 等代码检查器会将此类代码标记为可疑代码。

【讨论】:

  • 作为旁注,OP,您可能只想说 x++ 而不是 x = x++
  • 正确,但可能强调增量发生在 post 右手表达式评估,但 pre 分配到左侧,因此明显的“覆盖”
  • 这似乎是那些高中编程扭曲者之一......很好地清理了你的基础知识!
  • @Alberto - 很高兴听到您不将“专家”陈述视为“福音真理”。但是,验证我所说的更好的方法是咨询 JLS。您的编译/反编译测试仅表明我所说的对一个 Java 编译器有效。其他人可能(假设)表现不同......除了 JLS 不允许这样做。
  • 仅供参考:这最初发布到另一个问题,该问题作为此问题的副本关闭,现已合并。
【解决方案4】:
int x = 7;
x = x++;

It has undefined behaviour in C,对于 Java,请参阅 this answer。这取决于编译器会发生什么。

【讨论】:

  • 不,根据您引用的答案,它不依赖于编译器-请立即编辑--1
  • @Mr_and_Mrs_D 那要看什么?
  • 这是未定义的行为_仅适用于 C_。即使这样说它取决于编译器也是一种误导——这意味着编译器应该指定这种行为。我恢复投票但考虑编辑你的答案 - 编辑:哎呀我不能 - 你必须先编辑它:D
【解决方案5】:

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);
}

我还建议不要在大多数情况下在较大的表达式中使用 ++ 运算符。由于 when 的微妙性,它在前后增量中修改原始变量(分别为++xx++),很容易引入难以跟踪的细微错误下来。

【讨论】:

    【解决方案6】:

    According to Byte code从类文件中获取,

    两个赋值都递增 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
    
    • 这里的栈指的是操作数栈,本地:x 索引:1 类型:int

    【讨论】:

    • 你能详细解释一下你的答案吗?
    • 请看一下引用的链接和cmets
    【解决方案7】:

    后自增运算符的工作原理如下:

    1. 存储操作数的前一个值。
    2. 增加操作数的值。
    3. 返回操作数的前一个值。

    所以声明

    int x = 7;
    x = x++; 
    

    将被评估如下:

    1. x 被初始化为 7
    2. 后自增运算符存储 x 的先前值,即 7 以返回。
    3. 增加 x,所以现在 x 是 8
    4. 返回 x 的前一个值,即 7,并将其分配回 x,因此 x 再次变为 7

    所以 x 确实增加了,但由于 x++ 将结果分配回 x,所以 x 的值被覆盖为之前的值。

    【讨论】:

    • 但是在 msvc 中 x 是 8。在 gcc 和 clang x 中是 7。
    【解决方案8】:

    在“x = x++;”之后递增。如果您输入“x = ++x;”,则为 8。

    【讨论】:

    • 如果在x = x++之后递增,那么应该是8。
    【解决方案9】:

    在调用 x 之后递增,所以 x 仍然等于 7。调用 x 时 ++x 将等于 8

    【讨论】:

      【解决方案10】:

      当您重新分配 x 的值时,它仍然是 7。尝试 x = ++x,您将得到 8 其他操作

      x++; // don't re-assign, just increment
      System.out.println(x); // prints 8
      

      【讨论】:

        【解决方案11】:

        因为 x++ 在将值分配给变量之后会增加值。 依此类推,在执行此行期间:

        x++;
        

        变量 x 仍将具有原始值 (7),但在另一行再次使用 x,例如

        System.out.println(x + "");
        

        会给你 8 个。

        如果您想在赋值语句中使用递增的 x 值,请使用

        ++x;
        

        这将使 x 增加 1,然后将该值分配给变量 x。

        [编辑] 而不是 x = x++,它只是 x++;前者将 x 的原始值分配给它自己,所以它实际上在那一行什么都不做。

        【讨论】:

        • 一个说赋值后递增,一个说打印8。赋值前递增,打印7。
        • 如果x原来是7,System.out.println(String.valueOf(x++)); prints 7. 你确定我们说的是同一种编程语言?
        • 是的,我是。这个ideone.com/kj2UU 不打印 8,就像这个答案声称的那样。
        • 是的,我错了。 x = x++ 将在递增 x 之前先将 7 分配给 x。由于 x++(它本身就是一个赋值)在 x = (whatever) 之前首先解析,因此在 x=(whatever) 中分配给 x 的值将随之而来。抱歉,我没看到。
        • 实际上,增量是发生的第一件事ideone.com/xOIDU
        【解决方案12】:

        int x = 7; x = x++; 时会发生什么?

        ans -> x++ 表示先用 x 的值作为表达式,然后再增加 1。
        这就是你的情况。将 RHS 上的 x 值复制到 LHS 上的变量 x 中,然后将 x 的值增加 1。

        同理++x的意思是-&gt;先将x的值加一,然后在表达式中使用。
        所以在你的情况下,如果你这样做x = ++x ; // where x = 7
        您将获得 8 的值。

        为了更清楚,试着找出有多少个 printf 语句将执行以下代码

        while(i++ <5)   
          printf("%d" , ++i);   // This might clear your concept upto  great extend
        

        【讨论】:

        • 不正确 " RHS 上的 x 值被复制到 LHS 上的变量 x,然后 x 的值增加 1" - 这将使 x 为 8,但它是 7 - 递增发生在阅读和作业之间
        【解决方案13】:

        ++x 是预增量 -&gt; x 在之前被使用
        x++ 是后增量 -&gt; x 是增量 正在使用

        int x = 7; -> x get 7 value <br>
        x = x++; -> x get x value AND only then x is incremented
        

        【讨论】:

          【解决方案14】:

          所以这意味着: 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
          

          非常依赖编译器!

          【讨论】:

          • 谁说首先是平等的?
          • 如果我是你,我会立即把这些书扔掉 xD 无论如何,这就像 C 语言中的 (x = x + 1, x-1),允许使用逗号分隔的表达式。
          • @fortran:嗯,在我十年前的“Java 编程语言,第三版”第 159 页的副本中,它说“”表达式 i++ 等价于 i=i+1,除了 i只评估一次”。首先是谁说的?James Gosling,它会出现。这个版本的 Java 规范的这一部分非常模糊,指定的很差;我认为后来的版本清理了语言以表达实际运算符语义更清晰。
          • @fortran:通过“除了 i 只被评估一次”,标准试图传达像“M().x++”这样的表达式只调用 M() 一次。一个不那么模糊和更准确的措辞将强调 将 i 作为一个变量来确定其存储位置之间存在差异——这就是这里“只计算一次”的意思——和 读取或写入该存储位置——其中任何一个都可能是对“已评估”的合理但不正确的解释。显然,存储位置必须是可读写的!
          • “非常依赖编译器” - 一点也不!
          【解决方案15】:

          最简单的解释!

          这是因为 ++ 在操作数后递增之后,意味着首先将值分配给变量然后递增。如果您期望 x 值为 8,那么您应该像下面提到的那样预先增加它:

          【讨论】:

            【解决方案16】:

            x = x++;

            这是后增量运算符。应该理解为“使用操作数的值,然后增加操作数”。

            如果您希望相反的情况发生,即“增加操作数然后使用操作数的值”,则必须使用如下所示的预递增运算符。

            x = ++x;

            此运算符首先将 x 的值加 1,然后将值赋回 x。

            【讨论】:

              【解决方案17】:

              我认为这个争议可以在不进入代码和思考的情况下解决。

              将 i++ 和 ++i 视为函数,例如 Func1 和 Func2。

              现在 i=7;
              Func1(i++) 返回 7,Func2(++i) 返回 8(每个人都知道这一点)。在内部,这两个函数都将 i 增加到 8 ,但它们返回不同的值。

              所以 i = i++ 调用函数 Func1。在函数内部 i 递增到 8,但在完成时函数返回 7。

              所以最终 7 被分配给 i。 (所以最后,i = 7)

              【讨论】:

              • 这里没有有效的“争议”。代码可证明以特定方式运行,并且该行为符合 JLS。任何认为它表现不同的人要么没有尝试过,要么被迷惑了。 (这有点像说 7 x 7 是 49 当有人忘记了他们的时间表时“有争议”......)
              【解决方案18】:

              这是因为您使用了后自增运算符。 在以下代码行中

              x = x++;
              

              发生的情况是,您将 x 的值分配给 x。在将 x 的值分配给 x 之后,x++ 递增 x。这就是后增量运算符的工作方式。它们在语句执行后工作。因此,在您的代码中,x 先返回,然后再递增。

              如果你这样做了

              x = ++x;
              

              答案是 8,因为您使用了预增量运算符。这会在返回 x 的值之前先增加值。

              【讨论】:

                猜你喜欢
                • 2019-03-27
                • 2020-03-18
                • 2021-08-02
                • 2015-03-24
                • 2015-07-05
                • 2016-06-11
                相关资源
                最近更新 更多