1. ホーム
  2. java

[解決済み] なぜ無限ループになるのですか?

2022-03-20 03:53:26

質問

次のようなコードがあります。

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 を値とするか?

--update

以下はバイトコードです。

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

}

を読んでみる。 指示 を理解しようとすると...。

解決方法は?

注意事項 : 元々、この回答では説明のためにC#のコードを掲載しましたが、これはC#では int という参照によるパラメータがあります。 ref というキーワードがあります。を使って、実際に合法的なJavaコードで更新することにしたのですが、最初の MutableInt を近似するために、Googleで見つけた ref はC#で行う。それが答えの助けになるのか、妨げになるのか、私にはよくわかりません。私は個人的に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 の値を変更することはありません。 <サブ 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