-1

私はコードを持っています:

class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
      }
    }
  }

なぜ 1 が印刷されるのか理解できません。

4

5 に答える 5

6
try {
    ++a;
    return a; // 1 is returned here
} finally {
    a = 10; // a is assigned with 10 later.
}

の値aがインクリメントされ、tryブロック自体に返されます。この を投稿するreturnと、 の値がブロックaに再割り当てされfinallyます。そして、それが1を出力する理由です。


docsからの引用。これにより、より明確に理解できるはずです。

最終的にコンパイル

try-finally ステートメントのコンパイルは、try-catch のコンパイルと似ています。制御を try ステートメントの外部に移す前に、例外がスローされているため、通常の移管であるか突然の移管であるかにかかわらず、finally 句を最初に実行する必要があります。この簡単な例では:

void tryFinally() {
    try {
        tryItOut();
    } finally {
        wrapItUp();
    }
}

コンパイルされたコードは次のとおりです。

Method void tryFinally()
0   aload_0             // Beginning of try block
1   invokevirtual #6    // Method Example.tryItOut()V
4   jsr 14              // Call finally block
7   return              // End of try block
8   astore_1            // Beginning of handler for any throw
9   jsr 14              // Call finally block
12  aload_1             // Push thrown value
13  athrow              // ...and rethrow value to the invoker
14  astore_2            // Beginning of finally block
15  aload_0             // Push this
16  invokevirtual #5    // Method Example.wrapItUp()V
19  ret 2               // Return from finally block
Exception table:
From    To      Target      Type
0       4       8           any

コントロールが try ステートメントの外に渡される方法は 4 つあります。

  1. そのブロックの底から落ちることによって
  2. 戻ることによって
  3. break または continue ステートメントを実行することによって
  4. 例外を発生させることによって。
于 2013-10-29T07:12:20.467 に答える
1

これは、内部のコードが完了しfinallyた後に try..catch..finally のブロックが実行されるために発生します。try..catch

finallyで返された以前の値が割り当てられますtry

finally のコードは常に実行されますが、既に の値が返されていますtry

try {
    ++a;
    return a; 
  } finally {
    a = 10; 
  }

現在のa値は10、 の後returnです。良い習慣ではありませんが、デモ用です。

int a= 0;
try {
    ++a;
    return a; 
  } finally {
    a = 10;
    return a;
  }

returnです10

編集:

あなたの疑問:なぜエラーが発生しないのですか?

try-catch-finallyブロック内は異なります。同じブロックで同じことをして見てください。

try {
            ++a;
            return a;
            a=100;  //compiler error.
          } finally {
            a = 10;
          }

編集2

try-catch-finally の Java 言語仕様から:

try ステートメントはブロックを実行します。値がスローされ、try ステートメントにそれをキャッチできる 1 つ以上の catch 句がある場合、制御は最初のそのような catch 句に移されます。try ステートメントに finally 句がある場合、try ブロックが正常に完了したか突然完了したかに関係なく、また最初に catch 句に制御が与えられたかどうかに関係なく、別のコード ブロックが実行されます。

于 2013-10-29T07:12:53.827 に答える
0
class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
      }
    }
  }

上記のコードでは、try ブロックで返された値を最終的に更新しないため、返される値は 1 になります。

class Test {
  public static void main(final String [] args) {
    System.out.println(foo());
  }

  private static int foo() {
    int a = 0;
      try {
        ++a;
        return a;
      } finally {
        a = 10;
    return a;
      }
    }
  }

上記のコードは値を 10 として返します。これは、値が finally から再び返されるためです。

于 2013-10-29T07:24:11.330 に答える
0

JVM はスタックベースのマシンです。値をスタックにプッシュおよびポップします。Testクラスがどのように機能するかを理解するために、クラスを逆コンパイルしました。

private static int foo();
 Code:
   0: iconst_0        //push 0 to stack
   1: istore_0        //store 0 in the local variable 'a'(numbered 0). a==0
   2: iinc      0, 1  //increase the local variable 'a'(numbered 0) by 1. a==1;
   5: iload_0         //push value of the local variable 'a' onto the stack;
   6: istore_1        //store 1 in the local variable that not be declared(numbered 1);
   7: bipush    10    //push 10 onto the stack;
   9: istore_0        //store 10 in the local variable 'a'
  10: iload_1         //push onto stack value==1 of local variable that not be declared
  11: ireturn         //return 1
  12: astore_2
  13: bipush   10
  15: istore_0
  16: aload_2
  17: athrow
 Exception table:
 // not interesting ...
于 2013-10-30T07:20:45.317 に答える