53

次のコードを検討してください。

public class Action {
private static int i=1;
public static void main(String[] args) {
    try{
        System.out.println(i);
        i++;
        main(args);
    }catch (StackOverflowError e){
        System.out.println(i);
        i++;
        main(args);
    }
 }

}

私は4338正しく値を上げています。出力をキャッチした後、次のStackOverflowErrorように配線します。

4336
4337
4338 // up to this point out put can understand 
433943394339 // 4339 repeating thrice  
434043404340
4341
434243424342
434343434343
4344
4345
434643464346
434743474347
4348
434943494349
435043504350

ここでライブデモを検討してください。までは正常に動作していi=4330ます。実際、これはどのように起こるのですか?

ご参考までに:

ここで何が起こっているかを理解するために、次のコードを実行しました。

public class Action {

    private static int i = 1;
    private static BufferedWriter bw;

    static {
        try {
            bw = new BufferedWriter(new FileWriter("D:\\sample.txt"));
        } catch (IOException e) {
           e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        bw.append(String.valueOf(i)+" ");
        try {
            i++;
            main(args);
        } catch (StackOverflowError e) {
            bw.append(String.valueOf(i)+" ");
            i++;
            main(args);
        }
    }

}

現在、前号はありません。現在、i最大の値が16824744修正され、さらに実行されます。i=2,147,483,647問題なく (int の最大値) の値まで実行される可能性があります。

に問題がありprintln()ます。以下にも同様の回答があります。しかし、なぜ?

本当の理由は何でしょう?

4

7 に答える 7

4

私のテストによると:

try ブロックによって例外がスローされたi場合、catch ブロックに入ると同じ値になります (例外のためにインクリメントされないため)。

そして、catch ブロック内で同じ例外がスローされ、catch ブロックによって再びキャッチされます。

次のコードを試しました

try {
            System.out.println("Try " + i);
            i++;
            main(args);
        } catch (StackOverflowError e) {
            System.out.println("\nBefore");
            System.out.println("Catch " + i);
            i++;
            System.out.println("After");
            main(args);
            
        }

出力:

Try 28343
Try 28344
Before
Before
Before
Before
Catch 28344
After
Try 28345
Try 28346
Try 28347
Try 28348
Before
Before
Before
Before
Catch 28348
After
Try 28349

tryブロックが例外をスローすると、catchブロックによってキャッチされますが、System.out.println("Catch " + i);再度実行すると、例外が4回スローされます(私のEclipseでは)印刷なしSystem.out.println("Catch " + i);

上記の出力のように、印刷前に4回印刷される「前」のテキストを印刷してテストしましたSystem.out.println("Catch " + i);

于 2013-08-19T11:01:23.723 に答える
1

肝心なのは、それStackOverflowErrorは例外ではなくエラーだということです。例外ではなくエラーを処理しています。そのため、プログラムは catch ブロックに入ったときに既にクラッシュしています。プログラムの奇妙な動作については、この公式ドキュメントの Java バッファに基づいて以下に説明します。

たとえば、autoflush PrintWriter オブジェクトは、println または format が呼び出されるたびにバッファをフラッシュします。

は、バッファリングされる をSystem.out.println()内部的に呼び出します。PrintStreamバッファーからデータを失うことはありません。データがいっぱいになった後、または明示的にフラッシュを呼び出したときに、すべてが出力 (この場合は端末) に書き込まれます。

このシナリオに戻ると、スタックがどれだけいっぱいになるか、キャッチインから実行できた印刷ステートメントの数、main()およびそれらの文字数がバッファーに書き込まれたという内部ダイナミクスに依存します。ここで、最初の試行が実行された後、つまりスタック オーバーフローが最初に発生した場合、最初の System.out.println() は新しい行の出力に失敗したため、残りの文字でバッファをフラッシュしました。

于 2013-08-19T11:08:37.887 に答える
0

axtavt 回答は非常に完全ですが、これを追加したいと思います:

変数のメモリを格納するためにスタックが使用されることはご存知かもしれませんが、制限に達すると新しい変数を作成できないことに基づいて、System.out.println にはいくつかのスタック リソースが必要であることは事実です。

787     public void More ...println(Object x) {
788         String s = String.valueOf(x);
789         synchronized (this) {
790             print(s);
791             newLine();
792         }
793     }

次に、印刷を呼び出した後、エラーによりnewLineを呼び出すことさえできず、印刷時に再び壊れます。それに基づいて、次のようにコードを変更することで、それが事実であることを確認できます。

public class Action {
    static int i = 1;

    public static void main(String[] args) {
        try {
            System.out.print(i + "\n");
            i++;
            main(args);
        } catch (StackOverflowError e) {
            System.out.print(i + " SO " + "\n");
            i++;
            main(args);
        }
    }
}

これで、新しい行を処理するようにスタックに要求せず、定数 "\n" を使用し、例外出力行にデバッグを追加すると、同じ行に複数の値が出力されなくなります。

10553
10553 SO
10553 SO
10554
10554 SO
10554 SO
10555
10556
10557
10558

そして、新しいデータを割り当てて次の i 値に渡すためのリソースを取得するまで、壊れたままになります。

于 2013-09-09T19:10:56.797 に答える