なぜ無限ループになるのでしょうか? 質問する

なぜ無限ループになるのでしょうか? 質問する

次のコードがあります:

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

}

私はについて読みます説明書理解しようと努める...

ベストアンサー1

: もともとこの回答では、説明のためにC#コードを投稿しました。C#ではキーワードintを使用して参照渡しでパラメータを渡せるからですref。最初のコードを使用して、実際の合法的なJavaコードに更新することにしました。MutableIntGoogle で見つけたクラスは、C# で行われることとほぼ同じですref。これが回答に役立つか、害になるかはわかりません。個人的には 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

したがって、割り当てられる値の順序はx0、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です。実際には、 を注入しても上記のシナリオと何ら変わりはありません。次のようになります。xy

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 になります。


更新: ちなみに、上記の例の増分操作と割り当ての「間」で 1 が割り当てられるかどうか疑問に思わないようにx、この中間値は実行スレッドでは決して「表示」されないものの、確かに「存在する」ことを示す簡単なデモを用意しました。

デモでは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

おすすめ記事