关于finally的小启示
2012-11-17 19:17
197 查看
try/catch/finally语句下,finally子句是肯定会执行的。但是很多人做不同的测试,却得出了不同的结论。
具体的原理最好是去看《深入java虚拟机》,里面对jsr、ret等几个指令做了详细的说明。这里不深入分析,而仅仅是从表现形式上看一下finally的特征。
代码:
/*
* author: Zang XT
*/
public class TestFinal {
public static void main(String[] args) {
System.out.println("test1:"+testFinal1());
System.out.println("test2:"+testFinal2());
System.out.println("test3:"+testFinal3());
System.out.println("test4:"+testFinal4());
}
static int testFinal1(){
int i = 1;
try{
return i;
}
finally{
System.out.println("in testFinal1():finally 肯定会被执行的!");
i = 48;
}
}
static String testFinal2(){
String str = "try";
try{
return str;
}
finally{
System.out.println("in testFinal2():finally 肯定会被执行的!");
str = "finally";
}
}
static StringBuilder testFinal3(){
StringBuilder build = new StringBuilder("try ");
try{
return build;
}
finally{
System.out.println("in testFinal3():finally 肯定会被执行的!");
build.append("finally");
build = new StringBuilder("你猜我是谁!");
}
}
static String testFinal4(){
try{
return "return in try";
}
finally{
System.out.println("in testFinal4():finally 肯定会被执行的!");
return "return in finally";
}
}
}
输出是:
in testFinal1():finally 肯定会被执行的!
test1:1
in testFinal2():finally 肯定会被执行的!
test2:try
in testFinal3():finally 肯定会被执行的!
test3:try finally
in testFinal4():finally 肯定会被执行的!
test4:return in finally
结论很明显,finally的语句确实执行了,而且肯定是在方法return之前执行的,而且,如果finally中有return语句的话,方
法直接结束。这里需要注意的只有一点:在try中的return语句会将返回结果值压栈,然后转入到finally子过程,等到finally
子过程执行完毕之后(没有return),再返回。
下面具体看4个例子:
在testFinal1()中,return i;会将结果i的值,也就是1压入栈。即使在finally中将i修改了(i=48),也不回对已经压入栈里
的1造成任何影响。
在testFinal2()中,return str;将str的内容压入栈,比如我们假设str的内容为0x108(只是一个地址值),通过这个地址值我
们能找到"try",那栈里的内容就是0x108。执行str = "finally",这时候str这个变量的内容可能变为0x237了,这是
串"finally"的地址。方法调用结束后,返回的是什么?return时压入栈里的0x108。所以在打印结果时,我们打印的是通过
0x108找到的字符串"try"。
在testFinal3()中,return 压栈的是build这个变量的值,比如是0x3579,通过这个值我们可以找到StringBuilder对象。
finally语句块中对这个对象的内容进行了修改。build = new StringBuilder("你猜我是谁!");让build变量指向了一个新的
对象,这时候build的值可能是0x4579了。但是,别忘了,原来的StringBuilder对象仍然在0x3579处,而我们压栈的正是
0x3579啊!方法返回后,我们得到的返回值0x3579,通过这个引用值找到相应的StringBuilder对象,所以打印的结果是
test3:try finally。
在testFinal4()中,finally有return语句,直接返回,方法结束。
为什么不同的人有不同的结论?关键是没有正确理解压栈的是什么东西。其实初学java的时候,如果理解了变量是什
么,并区分引用和对象本身就不会得到错误的结论了。再有,如果理解java中,方法调用都是采用传值模式的话,这里也就
类似的可以明白了
具体的原理最好是去看《深入java虚拟机》,里面对jsr、ret等几个指令做了详细的说明。这里不深入分析,而仅仅是从表现形式上看一下finally的特征。
代码:
/*
* author: Zang XT
*/
public class TestFinal {
public static void main(String[] args) {
System.out.println("test1:"+testFinal1());
System.out.println("test2:"+testFinal2());
System.out.println("test3:"+testFinal3());
System.out.println("test4:"+testFinal4());
}
static int testFinal1(){
int i = 1;
try{
return i;
}
finally{
System.out.println("in testFinal1():finally 肯定会被执行的!");
i = 48;
}
}
static String testFinal2(){
String str = "try";
try{
return str;
}
finally{
System.out.println("in testFinal2():finally 肯定会被执行的!");
str = "finally";
}
}
static StringBuilder testFinal3(){
StringBuilder build = new StringBuilder("try ");
try{
return build;
}
finally{
System.out.println("in testFinal3():finally 肯定会被执行的!");
build.append("finally");
build = new StringBuilder("你猜我是谁!");
}
}
static String testFinal4(){
try{
return "return in try";
}
finally{
System.out.println("in testFinal4():finally 肯定会被执行的!");
return "return in finally";
}
}
}
输出是:
in testFinal1():finally 肯定会被执行的!
test1:1
in testFinal2():finally 肯定会被执行的!
test2:try
in testFinal3():finally 肯定会被执行的!
test3:try finally
in testFinal4():finally 肯定会被执行的!
test4:return in finally
结论很明显,finally的语句确实执行了,而且肯定是在方法return之前执行的,而且,如果finally中有return语句的话,方
法直接结束。这里需要注意的只有一点:在try中的return语句会将返回结果值压栈,然后转入到finally子过程,等到finally
子过程执行完毕之后(没有return),再返回。
下面具体看4个例子:
在testFinal1()中,return i;会将结果i的值,也就是1压入栈。即使在finally中将i修改了(i=48),也不回对已经压入栈里
的1造成任何影响。
在testFinal2()中,return str;将str的内容压入栈,比如我们假设str的内容为0x108(只是一个地址值),通过这个地址值我
们能找到"try",那栈里的内容就是0x108。执行str = "finally",这时候str这个变量的内容可能变为0x237了,这是
串"finally"的地址。方法调用结束后,返回的是什么?return时压入栈里的0x108。所以在打印结果时,我们打印的是通过
0x108找到的字符串"try"。
在testFinal3()中,return 压栈的是build这个变量的值,比如是0x3579,通过这个值我们可以找到StringBuilder对象。
finally语句块中对这个对象的内容进行了修改。build = new StringBuilder("你猜我是谁!");让build变量指向了一个新的
对象,这时候build的值可能是0x4579了。但是,别忘了,原来的StringBuilder对象仍然在0x3579处,而我们压栈的正是
0x3579啊!方法返回后,我们得到的返回值0x3579,通过这个引用值找到相应的StringBuilder对象,所以打印的结果是
test3:try finally。
在testFinal4()中,finally有return语句,直接返回,方法结束。
为什么不同的人有不同的结论?关键是没有正确理解压栈的是什么东西。其实初学java的时候,如果理解了变量是什
么,并区分引用和对象本身就不会得到错误的结论了。再有,如果理解java中,方法调用都是采用传值模式的话,这里也就
类似的可以明白了
相关文章推荐
- java关于try、catch、finally中的细节分析
- java关于异常处理只使用try-finally而不使用catch
- 关于try、catch、finally语句块中含有return语句的几点说明
- 关于虚数i和欧拉公式对旋转的一点启示
- Java:关于finally的说明
- java中关于try、catch、finally中的细节分析
- 关于编辑器和语言的一些启示
- 关于try ...catch .. finally的使用
- 关于 try..catch..finally
- 关于finally和finalize的使用
- Java中关于try、catch、finally的总结
- 关于Java finally的一个使用
- 关于 Java 中 finally 语句块的深度辨析
- java中关于try、catch、finally中的细节分析
- 暑期个人赛--第八场--B(关于手写队列的启示+题目有坑)
- 关于finally
- Python中关于try...finally的一些疑问
- try、catch、finally 关于return的先后执行顺序
- 关于Boolean==Boolean和Boolean=Boolean的启示
- 关于 Java 中 finally 语句块的深度辨析