try里面有return,finally 语句还执行么?执行的话是在return之前执行,还是之后执行。
答案:执行,return之前。
实例:
class test{
public int t() {
int i = 2;
try {
return i;
} finally {
i = 9;
System.out.println(i);
}
}
public static void main(String[] arsg) {
System.out.println(new test().t());
}
}
这个程序会输出什么:
9
2
。
为什么?
反编译一下:
C:\study>javap -c -v test
Compiled from "test.java"
class test extends java.lang.Object
SourceFile: "test.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #7.#21; // java/lang/Object."<init>":()V
const #2 = Field #22.#23; // java/lang/System.out:Ljava/io/PrintS
tream;
const #3 = Method #24.#25; // java/io/PrintStream.println:(I)V
const #4 = class #26; // test
const #5 = Method #4.#21; // test."<init>":()V
const #6 = Method #4.#27; // test.t:()I
const #7 = class #28; // java/lang/Object
const #8 = Asciz <init>;
const #9 = Asciz ()V;
const #10 = Asciz Code;
const #11 = Asciz LineNumberTable;
const #12 = Asciz t;
const #13 = Asciz ()I;
const #14 = Asciz StackMapTable;
const #15 = class #26; // test
const #16 = class #29; // java/lang/Throwable
const #17 = Asciz main;
const #18 = Asciz ([Ljava/lang/String;)V;
const #19 = Asciz SourceFile;
const #20 = Asciz test.java;
const #21 = NameAndType #8:#9;// "<init>":()V
const #22 = class #30; // java/lang/System
const #23 = NameAndType #31:#32;// out:Ljava/io/PrintStream;
const #24 = class #33; // java/io/PrintStream
const #25 = NameAndType #34:#35;// println:(I)V
const #26 = Asciz test;
const #27 = NameAndType #12:#13;// t:()I
const #28 = Asciz java/lang/Object;
const #29 = Asciz java/lang/Throwable;
const #30 = Asciz java/lang/System;
const #31 = Asciz out;
const #32 = Asciz Ljava/io/PrintStream;;
const #33 = Asciz java/io/PrintStream;
const #34 = Asciz println;
const #35 = Asciz (I)V;
{
test();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public int t();
Code:
Stack=2, Locals=4, Args_size=1
0: iconst_2 //push 2 onto the stack,将“2”加载到堆栈上
1: istore_1 //Pops an int off the stack and stores it in local variable <n>, store integer in local variable 1,取得堆栈值,存放到变量1
2: iload_1 //push integer in local variable 1 onto the stack,将变量1的值放入堆栈,此时值为“2”
3: istore_2 //store integer in local variable 2,将堆栈的值存放在变量2中,变量2值为2
4: bipush 9 //将9放入堆栈
6: istore_1 //将堆栈的值存入变量1,此时变量1的值为9
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;这里应该是加载System和PrintStream类
10: iload_1 //将变量1的值放入堆栈,堆栈值为9
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V打印
14: iload_2 //将变量2的值放入堆栈,此时为堆栈为“2”
15: ireturn //返回
16: astore_3 //Pops objectref (a reference to an object or array) off the stack and stores it in local variable <n>,
17: bipush 9 //
19: istore_1 //
20: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_1
24: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
27: aload_3 //push object in local variable 3
28: athrow
Exception table:
from to target type
2 4 16 any
16 17 16 any
LineNumberTable:
line 3: 0
line 5: 2
line 7: 4
line 8: 7
line 7: 16
line 8: 20
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 16
locals = [ class test, int ]
stack = [ class java/lang/Throwable ]
public static void main(java.lang.String[]);
Code:
Stack=3, Locals=1, Args_size=1
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: new #4; //class test
6: dup
7: invokespecial #5; //Method "<init>":()V
10: invokevirtual #6; //Method t:()I
13: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
16: return
LineNumberTable:
line 13: 0
line 14: 16
}
注意加黑的t()方法,里面注释是自己加的。参考自http://www.daimi.au.dk/dOvs/jvmspec/ref-Java.html,不一定完全正确(抽空看看jvm的书)
看test方法
0: iconst_2 //push 2 onto the stack,将“2”加载到堆栈上
1: istore_1 //Pops an int off the stack and stores it in local variable <n>, store integer in local variable 1,取得堆栈值,存放到变量1
2: iload_1 //push integer in local variable 1 onto the stack,将变量1的值放入堆栈,此时值为“2”
3: istore_2 //store integer in local variable 2,将堆栈的值存放在变量2中,变量2值为2
4: bipush 9 //将9放入堆栈
6: istore_1 //将堆栈的值存入变量1,此时变量1的值为9
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;这里应该是加载System和PrintStream类
10: iload_1 //将变量1的值放入堆栈,堆栈值为9
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V打印
14: iload_2 //将变量2的值放入堆栈,此时为堆栈为“2”
15: ireturn //返回
16: astore_3 //Pops objectref (a reference to an object or array) off the stack and stores it in local variable <n>,
17: bipush 9 //
19: istore_1 //
20: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_1
24: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
27: aload_3 //push object in local variable 3
28: athrow
带着注释的话应该能看懂,大家可以看到finally语句在return之前,但是怎么保证输出的是2而不是finally里改成的9呢。
istore_2 //finally之前将内容存入变量2
finally内容
14: iload_2 //将变量2的值放入堆栈,此时为堆栈为“2” //返回之前加载变量2
15: ireturn //返回
我们验证一下自己的观点:
class testTwo{
public int t() {
int i = 2;
try {
return i;
} finally {
}
}
public static void main(String[] arsg) {
System.out.println(new testTwo().t());
}
}
在这段代码里,finnaly语句什么也没干:
对应的结果是:
public int t();
Code:
Stack=1, Locals=4, Args_size=1
0: iconst_2
1: istore_1
2: iload_1
3: istore_2 //finally应该在两者之间,但是由于什么也没干,所以为空
4: iload_2
5: ireturn
6: astore_3
7: aload_3
8: athrow
Exception table:
from to target type
2 4 6 any
6 7 6 any
LineNumberTable:
line 3: 0
line 5: 2
line 6: 6
在整个3看看:
class testThree{
public int t() {
int i = 2;
try {
return i;
} finally {
int j=5;
j=3;
}
}
public static void main(String[] arsg) {
System.out.println(new testThree().t());
}
}
对应的结果为:
public int t();
Code:
Stack=1, Locals=6, Args_size=1
0: iconst_2
1: istore_1
2: iload_1
3: istore_2
4: iconst_5
5: istore_3
6: iconst_3
7: istore_3
8: iload_2
9: ireturn //可以看到返回之前,总是要加载变量2
10: astore 4
12: iconst_5
13: istore 5
15: iconst_3
16: istore 5
18: aload 4
20: athrow
Exception table:
然后我们把程序改为最简单的形式:
class testTwo{
public int t() {
int i = 2;
return i;
}
public static void main(String[] arsg) {
System.out.println(new testTwo().t());
}
}
对应的结果就是:
public int t();
Code:
Stack=1, Locals=2, Args_size=1
0: iconst_2
1: istore_1
2: iload_1
3: ireturn
LineNumberTable:
line 3: 0
line 4: 2
可以看到这里没有了变量2,因为你已经没有了finally
最后总结:
finally的语句应该是在return语句之前执行,但是为了保证值的不便,将值存放到一个新变量中,finally不管对变量如何操作,只要在返回之前加载新变量即可。