黑马程序员技术交流社区
标题:
finally语句的执行顺序问题
[打印本页]
作者:
周恺
时间:
2012-7-20 01:06
标题:
finally语句的执行顺序问题
看了一本书,上面说在try...catch....finally结构中,如果try里面有return语句,那么finally里面的语句还是会执行的
并且会在return语句以前就执行.但是自己做了下验证,却发现结果并非如此.发下代码:
public static void main(String[] args)
{
System.out.println(returnTest());//打印出的还是haha.
}
public static String returnTest()
{
String str="haha";
try
{
return str;//如果finally里面的语句会在return前面执行,那么这里打印的应该是hehe才对.
}
catch(Exception e)
{
}
finally
{
str="hehe";//这里改变了str的值
}
return null;
}
复制代码
但是如果我在finally里面换成是打印语句
finally
{
System.out.println("我在finally里面");
}
复制代码
打印结果却是:
我在finally里面
haha
这也印证了书上的说法,我想请问一下这是问什么?
作者:
丁二跃
时间:
2012-7-20 01:33
实验了一下确实如此……
但是仔细想了一下,应该是这样的:
首先 如果try里面有return语句,那么finally里面的语句还是会执行的
并且会在return语句以前就执行 这是绝对没错的
咱们 来看程序 当执行到 try 里的 return str 时候,准备返回str,这时返回的是什么呢?不是 haha 而是haha的 地址,这个地址会被放入 该函数的栈中,这是程序不会反会,去执行finally 里面的代码,虽然str指向变了,但是由于返回值已经确定。所以 还是返回原来的值……
作者:
杨_扬
时间:
2012-7-20 01:38
好问题,不过导致这种现象本身的原因并不在于try...catch...finally的执行顺序有什么奇怪,书上说的也没错,的确finally的部分会在return之前被执行,出现你说的这种现象是Java中另一种东西导致的,叫不可变类
String就是一个不可变类,也就是说当一个String变量被改变的时候,原先的变量值仍然被保存在栈内存中,作为garbage等着被回收器回收,新的值JVM会从新在栈内存中分配一片空间来存储。
另外还要介绍一点是,return到底返回的是什么,return返回的并不是一个具体的值,而是指向某个在函数名前面定义的类型的指针,在你的例子中就是返回一个String类型的指针
那么,这个问题就可以解决了,首先,你给str初始化为"hehe", 此时,栈内存中,JVM就开辟了一块内存存放hehe
当程序执行到了return语句的时候,一个指向"hehe"这片内存的指针就形成了,并且等待被函数返回调用出,不过此时,还有finally没有被执行,程序继续执行finally部分,你在其中改变了str的值,实际上是在栈内存中又开辟了一片空间来存储"haha"
finally被执行完,开始return先前生成的那个String指针,注意,这个指针指向的内存地址是存放"hehe"的,因此,我们可以得出如下结论,如果return的是一个不可变类的实例,那么,在finally语句对该实例进行更新是不会对return的值发生影响的
为了进一步验证这个观点,我稍微改变了一下你的程序,将String改为StringBuffer, StringBuffer是一个可变类,改变其实例的值后并不会在内存中重新开辟空间,而是在原有空间上进行修改
public static void main(String[] args) {
System.out.println(returnTest());// 打印出的还是haha.
}
public static StringBuffer returnTest() {
StringBuffer str = new StringBuffer("hehe");
try {
return str;
} catch (Exception e) {
} finally {
System.out.println("Finally");
str.append("haha");
}
return null;
}
复制代码
程序的执行结果是
Finally
hehehaha
看,str的值在return之后被finally中的语句改变了
作者:
王龙彪
时间:
2012-7-20 01:38
class Test
{
public static void main(String[] args)
{
System.out.println(returnTest());//打印出的还是haha.
}
public static String returnTest()
{
String str="haha";
try
{
System.out.println("try...");
return str;//如果finally里面的语句会在return前面执行,那么这里打印的应该是hehe才对.
}
catch(Exception e)
{
}
finally
{
return str="x... ...";//
}
}
}
复制代码
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
如果在finally里也加个return的话,就会返回最后赋的值了
作者:
周坤
时间:
2012-7-20 02:01
public class FinallyDemo{
public static void main(String[] args)
{
System.out.println(returnTest());//打印出的还是haha.
}
public static String returnTest()
{
String str="haha";
try
{
System.out.println(str);
return str;//[color=Red]先执行了return str,即确定了此方法的返回值,而后才执行的finally[/color]。
}
catch(Exception e)
{}
finally
{
System.out.println(str);
str="hehe";//这里改变了str的值
System.out.println(str);// [color=Red]这里输出一下str,发现为haha,说明的确改变了,但返回值依然指向“haha”
[/color] return str;
}
//return null;
}
}
复制代码
输出结果为
haha
haha
hehe
hehe
可以finally一般是用来关闭资源的,必须执行,而return是结束方法。程序先执行了try中的treturn,即确定了返回值指向“haha”,而后执行finally,其中str的值已经被附到了haha上,但是没有返回,如果加上return str;那么返回值将重新确认,最终输出的结果为haha
作者:
中国移动
时间:
2012-7-20 02:17
本帖最后由 中国移动 于 2012-7-20 02:20 编辑
哥们,给你来个直接的
try
{
//执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容
}
catch
{
//除非try里面执行代码发生了异常,否则这里的代码不会执行
}
finally
{
//不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
}
复制代码
补充下:
try catch语句一般用于处理异常的,catch里一般在try异常成立的情况下才会执行
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2