ホームページ > Java > &#&チュートリアル > Javaのreturn文とfinally文の実行順序は何ですか?

Javaのreturn文とfinally文の実行順序は何ですか?

PHPz
リリース: 2023-04-25 19:55:06
転載
1982 人が閲覧しました

ソース コード:

public class ReturnFinallyDemo {     public static void main(String[] args) {         System.out.println(case1());     }      public static int case1() {         int x;         try {             x = 1;             return x;         } finally {             x = 3;         }     } }  # 输出
ログイン後にコピー

上記のコードの出力は、次のように単純に結論付けることができます:finally の前に return が実行されます。バイトコード レベルで何が起こるかを見てみましょう。以下は、case1 メソッドのバイトコードの一部をインターセプトし、ソース コードと比較して、各命令の意味に注釈を付けます:

iconst_1 // 将常量1推入操作数栈顶  istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1;  iload_0 // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值推入栈顶  istore_1 // 弹出栈顶元素(1),保存到局部变量表slot[1],此时slot[1]=1。其实,此时就已经把要return的值准备好了  iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了  istore_0 // 弹出栈顶元素(3),保存到局部变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3;这里要注意的是,虽然都是更新了x的值,但是finally中的x和try中x的赋值,保存在了不同的局部变量表中 iload_1 // 将局部变量表slot[1]的值推入操作数栈顶,此时栈顶元素的值为1,是第3行指令保存的值  ireturn // 将操作数栈顶的值返回给调用方
ログイン後にコピー

バイトコードからは、ireturn のため、finally コードが最初に実行されるように見えます。この命令は実際に最後に実行されるため、返される値は誰が最初に実行するかには依存せず、ireturn 命令によって返されるオペランド スタックの最上位要素がいつ保存されるかによって決まります。上記のコード環境では、try コード ブロックで x に割り当てられたバージョン、つまり return ステートメントの直後に保存された x のバージョンです。

もう少し複雑なシナリオを見てみましょう:

public static int case2() {     int x;     try {         x = 1;         return ++x;     } finally {         x = 3;     } }  # 输出
ログイン後にコピー

上記の分析により、これは簡単に理解できます。バイトコードを見てみましょう:

iconst_1 // 将常量1推入操作数栈顶 istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1; iinc          0, 1 // 对局部变量表slot[0]进行自增(+1)操作,此时slot[0]=2,对应源码:++x;所以,可以看出return后面的表达式先执行 iload_0 // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值(2)推入栈顶 istore_1 // 弹出栈顶元素(2),保存到局部变量表slot[1],此时slot[1]=2。其实,此时就已经把要return的值准备好了 iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了 istore_0 // 弹出栈顶元素(3),保存到局部变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3;这里要注意的是,虽然都是更新了x的值,但是finally中的x和try中x的赋值,保存在了不同的局部变量表中 iload_1 // 将局部变量表slot[1]的值推入操作数栈顶,此时栈顶元素的值为2,是第6行指令保存的值,也就是经过++x之后的值 ireturn // 将操作数栈顶的值返回给调用方
ログイン後にコピー

As can上記のコードから分かるように、return 後の命令が最初に実行され、次にローカル変数テーブルに保存され、最後に のステートメントが実行され、最後に return 命令自体が実行されます。

まとめると、return 命令は最後に実行され、return の後に式がある場合、式の実行後にfinallyの文が実行され、return 命令が最後に実行されます。したがって、最初に実行されるか、最後に実行されるか、リターン命令が実行されるか: return 命令の後に式またはメソッド呼び出しがある場合、最初に実行され、次に最後に実行され、最後に return 命令が実行されます。上記のプログラムのデモの結果と同様に、x の代入だけでは最終的な戻り結果を判断することはできず、命令レベルで見ると、x への 2 つの代入はローカル変数テーブルの異なる場所に格納されます。

最後に、通常はこのようには書かれないシナリオを見てみましょう:

public static int case3() {     int x;     try {         x = 1;         return ++x;     } finally {         x = 3;         return x;     } } # 输出
ログイン後にコピー

これは、最終的に結果を返す例です。通常、このように書くことはお勧めできません。バイトコードの観点から分析しましょう:

iconst_1 // 将常量1推入操作数栈顶 istore_0 // 弹出栈顶元素(1),保存到局部变量表slot[0],此时slot[0]=1。这两条指令对应源码:x = 1; iinc          0, 1 // 对局部变量表slot[0]进行自增(+1)操作,此时slot[0]=2,对应源码:++x;所以,可以看出return后面的表达式先执行 iload_0  // 将局部变量表slot[0]的值推入操作数栈顶,也就是说把上面x的值(2)推入栈顶 istore_1 // 弹出栈顶元素(2),保存到局部变量表slot[1],此时slot[1]=2。 iconst_3 // 将常量3推入操作数栈顶,这一条指令开始,其实是开始执行finally中的代码了 istore_0 // 弹出栈顶元素(3),保存到变量表slot[0],此时slot[0]=3。这两个指令对应源码:x = 3 iload_0  // 将局部变量表slot[0]的值(3)推入操作数栈,这是跟之前不一样的地方,ireturn返回的值选择的局部变量表不一样 ireturn
ログイン後にコピー

以上がJavaのreturn文とfinally文の実行順序は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート