package com;public class TestTryCatch { public static void main(String args[]){
System.out.println(kkk());
}
public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
return k;
} finally {
k += 5;
}
}
}大家说这个程序的结果会输出什么?开始我认为输出为7,可是实际输出为2,但是经过调试,在程序返回前是要经过k += 5 这段代码的,并且通过观察点k的值是7,但是真正的输出却是2,这是为什么?
System.out.println(kkk());
}
public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
return k;
} finally {
k += 5;
}
}
}大家说这个程序的结果会输出什么?开始我认为输出为7,可是实际输出为2,但是经过调试,在程序返回前是要经过k += 5 这段代码的,并且通过观察点k的值是7,但是真正的输出却是2,这是为什么?
System.out.println(kkk());
} public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
return k;
} finally {
k += 5;
return k;
}
}
}
这样才返回7啊 应该返回值了啊
同样 如果try块中是return k+1; 那么结果是3
int k = 0;
int temp=0;
try {
k += 2;
temp=k; //return k;
} catch(Exception e){
k++;
temp=k; //return k;
} finally {
k += 5;
return temp;
}
你这样改下
public static void main(String args[]){
int i=kkk();
System.out.println(i);
}
我想这样也不能说明问题,问题主要是在finally代码块中已经执行了k+=5,这是事实,也就是在方法返回前k已经是7了
答:问题的核心是:方法真正返回的k值,不是你的方法返回前的那个值是7的k.
它记住的是"当时的"原因(即:记住的是当时return的k值),而不是你后来的那个k值.
看下例:
StringBuffer k = new StringBuffer();
try {
k.append(2);
return k;
} catch(Exception e){
k.append(3);
return k;
} finally {
k.append(5);
}
相当于:
StringBuffer k = new StringBuffer();
StringBuffer temp;
try {
k.append(2);
temp=k; //return k; 此时temp与k指向同一个对象!
} catch(Exception e){
k.append(3);
temp=k; //return k;temp与k指向同一个对象
} finally {
k.append(5);
return temp;
//由于temp与k指向同一个对象,对k的对象修改,如:在finally中执行的结果,当然就会产生作用啦.
}
反正不管怎样 我们已经有结论:在try里有return,finally还是会做,也就是说你的程序流程进入到try就一定会执行finally;
至于造成2这个结果的原因只是finally里并没有return k;
int k = 0;
try {
k += 2;
return k;
返回的是这个时候的k的值
finally 不影响返回的值
return 之后的值就是要返回的,往后的finally里面的代码不会改变值
System.out.println(kkk()); //4
} public static int kkk(){ //2
int k = 0;
try {
k += 2;
return k; //1
} catch(Exception e){
k++;
return k;
} finally {
k += 5; //3
}
}
} //1.已经返回给涵数int kkk()了.此时k = 2
//3接在1执行的.但却没有再把返回给涵数int kkk(),所以kkk()仍然是2
//4输出当然还是2啊!
* @param args
*/
public static void main(String[] args) {
// 返回值是引用类型
System.out.println(testReturn01());
// 返回值是值类型
System.out.println(testReturn02());
// 返回值是值类型,在finally中再次修改返回值
System.out.println(testReturn03());
}
public static StringBuilder testReturn01() {
StringBuilder sb = new StringBuilder("Init");
try {
return sb;
} catch (Exception e) {
} finally {
sb.append(" Changed");
}
System.out.println("Below Not Execute");
return sb;
}
public static int testReturn02() {
int i = 2;
try {
return i;
} catch (Exception e) { } finally {
i += 5;
}
System.out.println("Below Not Execute");
return i;
}
public static int testReturn03() {
int i = 2;
try {
return i;
} catch (Exception e) { } finally {
i += 5;
return i;
}
}
}上面程序的输出:
Init Changed
2
7
通过上面的程序大家要明白一下节点内容:
1.finally块不管在什么时候都是需要执行的,即使你在try块中return了
2.return其实就是给函数中的一个隐藏变量赋值(学过vb的同学应该都知道,vb中函数的返回值就是给函数名赋值),
所以你在try块中return的值会被finally中return的值覆盖掉。
3.引用类型和值类型的区别,引用类型指向的是同一个对象,一个改变大家都改变。值类型是每个人都有一份大家互不干扰。
StringBuilder是引用类型,所以在finally中改变的值会影响返回值,int是值类型所以再次改变i的值也不会影响到函数的隐藏变量的值!
希望对大家的学习有帮助!
public static List g(){
List li = new ArrayList();
try{
return li;
}catch(Exception e){
}finally{
li.add("xxxx");
li = null;
}
return null;
}
li的值就不是空的!所以不是引用型和原子类型的问题。
glacier3 这个提得好,无论是基本类型还是引用类型,return的都是一个temp,基本类型的话。temp保存的是数值,引用类型的话保存的是引用。有错请指教
System.out.println(kkk());
} public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
System.out.println(k);
return k; } finally {
k += 5;
System.out.println(k);
}
}
} try块没有抛出异常,当执行k += 2;之后就会执行return k; 此时计算出了k的值为2,再执行finally块中代码,但不会影响要返回的值。
同样 如果try块中是return k+1; 那么结果是3
支持二楼的!
try块没有抛出异常,当执行k += 2;之后就会执行return k; 此时计算出了k的值为2,再执行finally块中代码,但不会影响要返回的值。
同样 如果try块中是return k+1; 那么结果是3
是这个样子地
不管是否抛出异常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:1in testFinal2():finally 肯定会被执行的!test2:tryin testFinal3():finally 肯定会被执行的!test3:try finallyin 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中,方法调用都是采用传值模式的话,这里也就类似的可以明白了。
http://www.blogjava.net/fhtdy2004/archive/2009/04/30/268386.html
http://old.blog.edu.cn/user1/16293/archives/2006/1248335.shtml
不知道看不看得懂。
System.out.println(kkk());
} public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
return k;
} finally {
k += 5;
return k;
}
}
}
这位哥们说的不错,就是这样了
同样 如果try块中是return k+1; 那么结果是3
int temp=0;
try {
k += 2;
temp=k; //return k;
} catch(Exception e){
k++;
temp=k; //return k;
} finally {
k += 5;
return temp;
}
finally的作用就是执行一些必要的代码,比如在程序抛出异常终止后,他还是会执行,所以一般用它来关闭数据库连接等一些必要也很重要的操作.
综合我上面说的这两点,你可以试一下,不管你是执行try里面的代码,甚至有return,还是执行catch里面的代码,finally都会照常执行.
只是在我这道题里面,之前已经返回了2,所以函数的返回结果是2,而finally执行后的结果对这个是没有影响的,它是在return之后执行的.
那么值就会变为7
System.out.println(kkk());
} public static int kkk(){
int k = 0;
try {
k += 2;
return k;
} catch(Exception e){
k++;
return k;
} finally {
k += 5;
}
}
}
下面是对的,请看:
package com; public class TestTryCatch { public static void main(String args[]){
System.out.println(kkk());
} public static int kkk(){
int k = 0;
try {
k += 2; } catch(Exception e){
k++;
return k;
} finally {
k+=5;
}
return k;
}
} 好好比较一下,看看你错在什么地方?
一个 try-catch-finally(其中finally块用于清除try块中分配的任何资源以及运行任何既使在发生异常时也必须执行的代码.)
一个 return 问题.
一个 调试问题.
综合三者.跟大家指出的问题.LZ应该明白了.
try 快里面k += 2 没有报错 遇到了 return k 所以返回了k,下面的代码不执行了,
不懂别乱说好不好,finally块里的是必定执行的,无论有没有报错。
....
} ctach {
....
} finally {
....
}
1.finally块肯定要执行
2.return 返回点的选择楼上很多人说的已经很清楚了,说下自己的看法,不知道大家注意到没有 :try {
int i = 0;
} ctach {
// System.out.println(i); 错误
}我想表达的意思这是一个“数据堆栈区域的问题”,try ,catch ,finally 分别开辟的是独立的存储区域。
这样在finally对变量的操作相当是"函数的传参" 这又回归到java的基础,"值传递"的问题,结合return返回点的选择,这样的话是能够很好的解释以上大家遇到的问题。
不知道自己的想法对不?还希望指点!谢谢
再说为什么返回值是2。个人认为,可以这么理解。finally是在return一句执行后,方法栈消失前执行。这样就可以很轻松的解释他返回2。应该在方法栈消失前
他就返回了一个值。当int等基础类型时返回的是值,当对象时,返回的是地址。所以如果不是int肯定只变了。return时值是没变的,在方法栈消失前被finally改了,且因为返回的是地址,所以外面取的到值自然变化。
所以往下就不走了
String不是基本类型,同样适用~