Javaの最終的なキーワードは、通常、Try Catchブロックで使用されます。メソッドが終了する前、または例外が発生したときにいくつかのリソースリリース操作を実行するために使用されます。最近、インターネット上のいくつかの記事が、Try Catchの実行の順序について最終的にキーワードを議論しているのを見てきましたが、最終的にブロックがメソッドの最後に実行されることが与えられています。
これらの見解は、一般的にそれを信じています:
1)最終的なキーワードは、プログラムが返された後、前のメソッドに戻る前に実行されます。返品値は一時的なエリアで保存されます。最終ブロックが実行されると、一時的な領域の値が返されます。
2)最終的なブロックに戻り値がある場合、プログラムの前のTRYまたはCACTブロックの一時的な領域に保存された値を置き換えます。
しかし、問題は本当にこれが好きですか?注意深く考えてみましょう。 JVMは、実行時にバイトコード命令を説明および実行します。それがreturnステートメントを実行したとき、彼は最終的にブロックがあるかどうかを知りませんか?最終的にブロックがない場合はどうなりますか?それがバイトコード命令であるか、コンピューター命令であるかを明確にする必要があります。 JVMはそれほど賢くありません。同じ命令は明確でなければならず、2つの意味は含まれません。したがって、実行中のreturnステートメントが何であれ、スタックのコンテンツがポップアップされ、呼び出し方法に返されます。
同時に、「Java Virtual Machineに深く」という本が別の説明をしていることがわかります。 Javaコンパイラが最終句をコンパイルすると、JSR命令が生成されます。これにより、JVMは、実行のために、つまり最終的なブロックでのミニサブルーチンに呼び出されます。同時に、プログラム内のreturn 0ステートメントは、JSR命令を呼び出す前にローカル変数のスタック内の戻り変数にコンパイルされ、JSR命令が呼び出され、最終的にブロックが実行され、最終的にブロックが戻ります。ローカル変数の戻り値がスタックに押し込まれると、iRETURN命令が実行され、戻り値がスタックからポップアップし、コールメソッドに戻ります。ここでは、JSR命令を実行する前に、local変数に返品値が保存されます。これは、最終的なブロックの実行中に例外が発生する可能性があるか、返品値もあるためです。この方法でのみ、最終的なプログラム実行の一貫性を確保できます。 「Java Virtual Machineの深化」はしばらく書かれているため、著者が使用するJVMコンパイラの実装とバージョンも、この記事で説明したものとは異なります。そのため、テスト後、さまざまなコンパイラの実装または同じプログラムのバージョンのバージョンのバイトコードの生成にわずかな違いがあります。興味がある場合は、この本の最終的な句によって生成されたバイトコードを見ることができます。
この記事のバイトコード生成は、OracleのJDK8U-25バージョンのコンパイラによってコンパイルおよび生成されます。
以下の例を見てみましょう。
1.ついにキャッチすることを試してください例:
public class finalltest {public static void main(string [] args){int r = test(); System.out.println(r); } public static int test(){try {system.out.println( "try"); // 1/0を返します; 0を返します。 } catch(Exception e){System.out.println( "Exception"); 100を返します。 }最後に{system.out.println( "fully"); }}}Tryブロックでreturn 0ステートメントを使用し、プログラムの実行結果は次のとおりです。
試す
ついに
0
Tryブロックで1/0ステートメントを返すと、プログラムが実行された結果は次のとおりです。
例外
ついに
100
実際、実行中の結果を通じて、TryまたはCatchブロックでの返信ステートメントの前に、最終的なブロックが他のステートメントの後に実行されることがわかります。言い換えれば、JVMがBytecodeを解釈して実行するため、プログラムの執筆順序は実行命令と一致しません。そのため、Javaコンパイラがこのコードをコンパイルする方法を確認し、ByteCodeによって生成されたものを確認する必要があります。
2。プログラムによって生成されたbytecodeの一部:( Java bytecode命令を参照してください)
public static int test();記述子:()Iフラグ:acc_public、acc_static code:stack = 2、locals = 2、args_size = 0 0:getstatic#20 // field java/lang/system.out:ljava/io/printstream; 3:LDC#36 // String Try 5:InvokeVirtual#38 // Method Java/io/printStream.println :( Ljava/Lang/String;)v 8:GetStatic#20 // Field Java/Lang/System.out:ljava/io/printstream; 11:LDC#41 //文字列最終的に13:InvokeVirtual#38 // Method Java/io/printStream.println :( Ljava/Lang/String;)v 16:Iconst_0 17:Ireturn 18:Store_0 19:GetStatic#20 // Field Java/System.out:Ljava/io/printStream; 22:LDC#43 //文字列例外24:InvokeVirtual#38 //方法Java/io/printStream.println :( ljava/lang/string;)v 27:getStatic#20 // field Java/lang/system.out:ljava/io/printstream; 30:LDC#41 // Stringが最後に32:InvokeVirtual#38 // Method Java/io/printStream.println :( Ljava/Lang/String;)v 35:Bipush 100 37:Ireturn 38:Store_1 39:GetStatic#20 // Field Java/Lang/System.Out:Ljava/io/io/io/io 42:LDC#41 //文字列最後に44:InvokeVirtual#38 // Method Java/io/printStream.println :( ljava/lang/string;)v 47:aload_1 48:Athrow例外テーブル:ターゲットタイプタイプ0 8 18クラスJava/Lang/exception
赤い部分から、10行目と11行目が最終的にブロックされたステートメントの指示に対応していることがわかります。16と17は、戻る前に、Tryブロックに関する他のステートメントの後、0の命令に対応しています。 19および20は最終的にブロック命令に対応し、21と22は100のステートメントを返す命令に対応します。他の声明をキャッチし、戻る前に、これらすべてが起こることは、Javaコンパイラが私たちのためにこれをすべて行ったことです。プログラムで発生する例外に関しては、JVMは、例外テーブルから例外を処理するための対応するアドレスの場所を見つけます。
したがって、最終的にブロックのステートメントは、Tryブロックの前にJavaコンパイラによって挿入され、ブロックリターンステートメントをキャッチし、他のステートメントの後に挿入されると結論付けることができます。ここでJSRコールを生成するサブルーチンはありません。そのため、Tryブロックを実行したり、Catchブロックを実行したりするかどうかにかかわらず、メソッドが戻る前に最終的なブロックが実行されます。
Javaブロックの実行タイミングの上記の包括的な分析は、私があなたと共有するすべてのコンテンツです。参照を提供できることを願っています。wulin.comをもっとサポートできることを願っています。