Maison > Java > javaDidacticiel > Quel est l'ordre d'exécution des instructions return et enfin en Java ?

Quel est l'ordre d'exécution des instructions return et enfin en Java ?

PHPz
Libérer: 2023-04-25 19:55:06
avant
1979 Les gens l'ont consulté

Code source :

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;         }     } }  # 输出
Copier après la connexion

La sortie du code ci-dessus peut simplement conclure que return est exécuté avant de finalement jeter un coup d'œil à ce qui se passe au niveau du bytecode. Ce qui suit intercepte une partie du bytecode de la méthode case1, et le compare avec le code source pour annoter la signification de chaque instruction :

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 // 将操作数栈顶的值返回给调用方
Copier après la connexion

D'après le bytecode, il semble que le code final soit exécuté en premier, car l'instruction ireturn est bien in Il est exécuté en dernier, donc la valeur renvoyée ne dépend pas de qui l'exécute en premier, mais du moment où l'élément supérieur de la pile d'opérandes renvoyé par l'instruction ireturn est enregistré. Dans l'environnement de code ci-dessus, il s'agit de la version attribuée à x dans le bloc de code try, c'est-à-dire la version de x enregistrée immédiatement après l'instruction return.

Regardons un scénario légèrement plus compliqué :

public static int case2() {     int x;     try {         x = 1;         return ++x;     } finally {         x = 3;     } }  # 输出
Copier après la connexion

Avec l'analyse ci-dessus, cela est facile à comprendre. Jetons un coup d'œil au bytecode :

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 // 将操作数栈顶的值返回给调用方
Copier après la connexion

Comme le montre le code ci-dessus, après le retour, l'instruction est. exécuté en premier, puis enregistré dans la table de variables locales, puis l'instruction infinally est exécutée et enfin l'instruction de retour elle-même est exécutée.

Pour résumer, l'instruction de retour est exécutée en dernier. S'il y a une expression après return, l'instruction infinally sera exécutée après l'exécution de l'expression, et l'instruction de retour sera exécutée en dernier. Alors lequel est exécuté en premier, enfin ou return : s'il y a un appel d'expression ou de méthode après l'instruction return, il sera exécuté en premier, puis enfin, et enfin l'instruction return. Tout comme le résultat de la démonstration du programme ci-dessus, le résultat final du retour ne peut pas être jugé uniquement à partir de l'affectation de x. Au niveau instruction, les deux affectations à x sont stockées à des emplacements différents dans la table des variables locales.

Enfin, regardons un scénario qui n'est généralement pas écrit comme ceci :

public static int case3() {     int x;     try {         x = 1;         return ++x;     } finally {         x = 3;         return x;     } } # 输出
Copier après la connexion

Ceci est un exemple de résultats finalement renvoyés. Il n'est pas recommandé d'écrire comme ceci. Analysons-le du point de vue du bytecode :

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
Copier après la connexion
.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal