小编典典

为什么会进入无限循环?

all

我有以下代码:

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

我们知道他应该只写x++or x=x+1,但x = x++应该首先在其上归因x于自身,然后再增加它。为什么x继续使用0as 值?

- 更新

这是字节码:

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

}

我将阅读有关说明以尝试理解…


阅读 100

收藏
2022-03-13

共1个答案

小编典典

注意 :最初我出于说明目的在此答案中发布了 C# 代码,因为 C#
允许您通过关键字int的引用传递参数ref。我决定使用MutableInt我在
Google 上找到的第一个类用实际合法的 Java 代码来更新它,以近似refC#
中的功能。我真的不知道这是否有助于或伤害答案。我会说我个人还没有做过那么多的 Java 开发。所以据我所知,可能有更多惯用的方法来说明这一点。


也许如果我们写出一个方法来做相当于做什么x++,它会更清楚。

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

正确的?递增传递的值并返回原始值:这就是后自增运算符的定义。

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

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

postIncrement(x)做什么?增量x,是的。然后 返回 增量之前的x 内容 。然后将此返回值分配给x.

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

如果我们重写上面的代码,这可能会更清楚:

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.

您对这样一个事实的关注,即当您用 替换x上述赋值的左侧时y,“您可以看到它首先增加 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.

所以很明显:x = x++实际上不会改变 x 的值。它总是导致 x 具有值 x 0,然后是 x 0 + 1,然后是 x 0。


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

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

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

启动后台线程...
0
0
1
1
0
0
0
0
0
0
0
0
0
0
1
0
1
2022-03-13