为什么这个程序会进入无限循环?

509

我有以下的代码:

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赋值给自己,然后再将其递增。为什么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

}

我会阅读有关指令的内容,以尝试理解...


8
我猜测正在发生的事情是:1.将x加载到寄存器中(=0); 2.将x增加(x=1); 3.将寄存器值保存到x中(x=0)。在C/C++中,这将导致未定义的行为,因为没有正式的序列点来定义2和3的顺序。希望有人能引用Java规范中与此相等的内容。 - Rup
19
我们尝试在 C++ 中运行这个程序,结果打印出了 1、2、3 并退出了。我没想到会这样。我猜这是编译器相关的,因为这是未定义的行为。我们使用的是 GNU 的 g++ 编译器。 - grieve
14
@saj,x++是后自增;x=结果的赋值;x++的结果是原始的x(虽然有一个增量的副作用,但这不会改变结果),因此可以解释为var tmp = x; x++; x = tmp; - Marc Gravell
5
既然我有一个受欢迎的问题,我感到后悔了。即使选择了正确答案,重复的回答仍不停地涌现。我的“最近活动”页面满是相同的答案,而且还在继续增加... - The Student
3
@Rob Vermeulen,在发表评论之前,您可能需要阅读完整的问题.. ;) 这是我的一个学生编写的代码,我想知道这种行为的原因。 - The Student
显示剩余18条评论
26个回答

0

x++ 表达式的值为 x++ 部分影响 评估 后的值,而不是 语句 后的值。 因此,x = x++ 实际上被翻译为

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

0

这是因为它是后增量。这意味着变量在表达式求值之后递增。

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

x现在是10,但y是9,在它被递增之前x的值。

更多信息请参见后置递增定义


1
你的 x/y 示例与实际代码不同,并且差异是相关的。你的链接甚至没有提到 Java。对于其中提到的两种语言,问题陈述是未定义的。 - Matthew Flaschen

0

我想知道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

或者

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

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

我会非常谨慎地编写依赖于这种行为的代码。在我看来,它看起来非常依赖于实现,而且在规范之间存在漏洞。唯一会有所区别的时候是如果你做了一些疯狂的事情,比如这里的例子,或者如果你有两个线程运行并且依赖于表达式内部的评估顺序。


0

这不是一个优先级的问题。在C和C++中,++的优先级比=高,但该语句是未定义的。 - Matthew Flaschen

0
在将值增加一之前,该值被分配给变量。

-1

自增运算符应用于与您正在分配的变量相同的变量。那是在寻找麻烦。我相信您可以在运行此程序时看到x变量的值....这应该说明为什么循环永远不会结束。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接