大家看看以下代码:public static String fun(){
String s = "abc";
try{
throw new Exception();
} catch (Exception e) {
return s;
} finally{
s = "s";
}
}你们是怎么样理解的?
String s = "abc";
try{
throw new Exception();
} catch (Exception e) {
return s;
} finally{
s = "s";
}
}你们是怎么样理解的?
请看代码 static String s = "abc"; public static String fun() {
try {
throw new Exception();
} catch (Exception e) {
return s;
} finally {
s = "s";
}
} public static void main(String[] args) throws Exception {
System.out.println(T1.s);
System.out.println(T1.fun());
System.out.println(T1.s);
}
static String s = "abc"; public static String fun() {
try {
throw new Exception();
} catch (Exception e) {
return s;
} finally {
System.out.println("in finally");
s = "s";
}
} public static void main(String[] args) throws Exception {
System.out.println(Test.s);
System.out.println(Test.fun());
System.out.println(Test.s);
}debug了一下
发现return是在finally调用之后才执行的
至于返回的是“abc”就不知道是什么原因了
例如下面的程序:package basic;import java.util.HashMap;
import java.util.Map;public class TryFinal {
Map<String, String> x = new HashMap<String, String>();
volatile long dd = 0L;public long returnLong() {
dd = 99;try {
dd = 100;
return dd;
} finally {
dd = 88;
}
}public Map returnMap() {try {
x.put("8","8");
return x;
} finally {
//x = new HashMap<String, String>();
x.put("7", "7");
}}public static void main(String[] args) {
TryFinal t = new TryFinal();System.out.println( t.returnLong() ); //输出100System.out.println( t.dd ); //输出88Map m = t.returnMap();System.out.println(m); //输出{7=7, 8=8}
System.out.println(t.x); //输出{7=7, 8=8}System.out.println(m==t.x); //输出true}
}
在这种结构的程序中, 如果返回是基础类型的值, 那么finally中进行的修改是会反映到示例中的值的, 但是却不会影响到方法返回给调用者的结果. 这很好的印证了"java中只有值传递". 调试过程中也发现, 是先执行了return dd; 再跳到finally中执行dd=88; 再跳到 return dd; 所以我大胆的设想,在sun的jvm实现中, 方法内部有一个我们看不到的"返回变量", 在第一次执行return dd;的时候就被赋值为100, 最后返回的自然就是100. 而示例内的dd, 因为被finally段的dd=88;修改了, 自然就保持了88但是如果返回类型是对象类型, 情况又不同. 同样基于上述假设, 调试过程中看到的也是相同的运行过程, 但是这个看不到的"返回变量"却被赋予了真正对象的内存地址, 也就是一串符号表示. 因此, 被返回的Map对象和t对象中引用到的Map对象其实是同一个, 则很明显finally中对Map对象进行的修改就反映在System.out.println(m); //输出{7=7, 8=8}这个输出里面了, 而且最后的一句"System.out.println(m==t.x); //输出true" 也能证明这点.留意这句, //x = new HashMap<String, String>(); 如果把注释去掉, 那么System.out.println(m==t.x); 就输出false了
工作原理:在方法体中始终抛出异常,被捕获后执行catch后的代码。可以构造如下类来测试:public class Tester {
static String s = "abc"; public static String fun() {
try {
throw new Exception();
} catch (Exception e) {
return s;
} finally {
s = "s";
}
} public static void main(String[] args) {
String str = new Tester().fun();
System.out.println(str);
}
}
运行结果:
abc
public class Tester {
static String s = "abc"; public static String fun() {
try {
throw new Exception();
} catch (Exception e) {
return s;
} finally {
s = "s";
}
} public static void main(String[] args) {
String str = new Tester().fun();
System.out.println(str);
System.out.println(s);
}
}
运行结果:
abc
s
try{
throw new Exception();
} catch (Exception e) {
return "123";
} finally{
return "abc";
}
}
返回的值是对象"abc" ,s指向了新的值"s"
try {
throw new Exception();
} catch (Exception e) {
System.out.println("return");
return s;
} finally {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("finally");
s = "s";
}
} public static void main(String[] args) throws Exception {
Test T1 = new Test();
System.out.println(T1.s);
System.out.println(T1.fun());
System.out.println(T1.s);
}打印结果:
abc
return
(有停顿)
finally
abc
s
finally一般用作关闭资源 释放资源
static String s;
特别是建议不要用static用了static,变量的性质发生了很大的变化
无法说明楼主的问题吧
String s = "abc";
s 是个局部变量如果你加了static的话
s就变成了全局的静态变量static的用法不要我说了吧
在任何一处更改都会受影响如果把这个变量加上static
那讨论try,catch,finally,有何意义?
更何况里面还有return
而且 在这里 我就是故意改成成员变量来说明问题的
和朋友讨论了一下,似乎应该是这样的程序执行到return s;的时候,只是把返回值放到了方法的调用处
但是,这个时候方法并没有结束,因为还有finally块没有执行
也就是说严格的讲finally块应该是在return后面执行的
但是在finally里面只是给s赋值,所以这个并没有影响到返回值如果,程序变成下面这个样子public static String fun(){
String s = "abc";
try{
throw new Exception();
} catch (Exception e) {
return s;
} finally{
s = "s";
return s;
}
}那末打印出来的就是 s 了
因为在finally里面刷新了返回值
而finally总是会被执行,在跳出函数前,finally内的代码得到了执行的机会,从而使 s = "s";另:就算返回类型是对象类型,还是值传递,只不过因为对象变量内放的是引用的地址,返回时是引用的地址的一份拷贝,而不是整个对象实例的拷贝(那变成克隆了)。根据推荐的java规范,一个函数只能有一个retrun,那么显然retrun应该放在“踹开吃”外面,楼主的这种写法是不规范的。
public Map returnMap() {
try {
x.put("8", "8");
return x;
} finally {
// x = new HashMap <String, String>();
x.put("7", "7");
}
}public String fun(){
String s = "abc";
try{
throw new Exception();
} catch (Exception e) {
return s;
} finally{
s = "s";
}
}public String fun2(){
try{
throw new Exception();
} catch (Exception e) {
return "123";
} finally{
return "abc";
}
}
我的解释是这样:
String 显然是对象,在catch里碰到了return,此时已经拷贝了String对象的地址到了程序返回的变量(如大伙所说的)
然后,程序进入了finally 语句块,此时 变量 s 指向了另外一个String对象"s"(原因String是被final修饰的)所以程序返回的变量的值仍然指向 "abc" 的地址。
对于map的解释:
因为HashMap是没被final 修饰,
所以程序返回的变量 与finally里修改的map的实例指向同一个地址。
所以返回的Map实例是包含了两个键值对.
对于catch和finally 都有return的情况,我的解释是:当程序跑到catch里的return时,则程序的返回变量的值 此时指向了 当前return的值,然后程序继续执行finally的return,此时程序的返回变量值会覆盖了先前的值,所以程序真正返回 又会是finally里return的值
守护线程一般是为非守护线程服务的 其他线程关闭了 守护线程也完成工作了 所以开着也没什么用 就关了
这种设计是很科学的所以不是finally不会执行 而是jvm已经终止了 后面的任何程序段都不会执行
当执行到这里面时如果有异常则进入catch反之则不会执行catch,
而finally是不管有没有异常都会执行的代码块。
在catch已经返回s="abc"
之后才对s重新赋值
只有catch中有return
所以输出的是abc
public static void main(String[] args) {
String str = fun();
PrintUtil.print("return");
PrintUtil.print(str);
}
public static String fun(){
String s = "abc";
try{
throw new Exception();
} catch (Exception e) {
return fun2(s);
} finally{
s = "s";
PrintUtil.print("finally");
}
}
public static String fun2(String s){
PrintUtil.print("in fun2 s=" +s);
return s;
}
}
执行结果:
in fun2 s=abc
finally
return
abc即: 在finally前执行了return语句, 但是并没有真正的返回, 而是去执行了finally,
然后再将结果返回.
于是做了一下更改:
1. 将fun2的返回值改为其他值, 则整个fun的返回值等于fun2的返回值
2. 在finally里添加return语句, 则整个fun的返回值等于finally里的返回值.