论坛首页 Java企业应用论坛

关于java中,try/catch执行的问题

浏览 3701 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-08-31  

今天无意中,同事发现了一个有趣的现象,首先来看一下以下代码:

java 代码会发现,18行加载了一下变量b中的值,所以,其实,在执行代码的第8行时,并不是执行return,而只是往内存中存储变量b的值。

  1. public class Test {   
  2.     private static int todo() {   
  3.         int b=1;   
  4.         try{   
  5.             int a=2/0;   
  6.         } catch(Exception e) {   
  7.             System.out.println("in catch");
  8.             return 1;   
  9.         } finally {   
  10.             System.out.println("in final");   
  11.         }   
  12.         return 2;   
  13.     }   
  14.     /**  
  15.      * @param args  
  16.      */  
  17.     public static void main(String[] args) {   
  18.         System.out.println(todo());   
  19.   
  20.     }   
  21. }  

此时,运行结果为
in catch
in final
1

看到这里,少部分人已经开始不明白了,我们继续看另一则代码(请注意细小的差别):

java 代码
  1. public class Test {      
  2.     private static int todo() {      
  3.         int b=1;      
  4.         try{      
  5.             int a=2/0;      
  6.         } catch(Exception e) {      
  7.             System.out.println("in catch");   
  8.             return b;      
  9.         } finally {      
  10.             System.out.println("in final");      
  11.         }      
  12.         return 2;      
  13.     }      
  14.     /**    
  15.      * @param args    
  16.      */     
  17.     public static void main(String[] args) {      
  18.         System.out.println(todo());      
  19.      
  20.     }      
  21. }     

此时,运行结果依旧是
in catch
in final
1

但是通过单步执行,会发现,两种代码的执行顺序有少许差别

第一种代码的try/catch单步执行顺序为
7->10->8

第二种代码的try/catch单步执行顺序为
7->8->10->8

这里我们对其进行了研究,从中间码入手,首先来分别看看两者的中间码:

上述第一块代码的中间码
  1. 11  ldc <String "in catch"> [22]   
  2. 13  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  3. 16  getstatic java.lang.System.out : java.io.PrintStream [16]   
  4. 19  ldc <String "in final"> [30]   
  5. 21  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  6. 24  iconst_1   
  7. 25  ireturn  

可以发现,明显的执行顺序,1行把装入字符串转入内存,2行打印,4行在把字符串装入内存,5行再打印,7行返回

上述第二块代码的中间码
  1. 13  ldc <String "in catch"> [22]   
  2. 15  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  3. 18  iload_0 [b]   
  4. 19  istore_3   
  5. 20  getstatic java.lang.System.out : java.io.PrintStream [16]   
  6. 23  ldc <String "in final"> [30]   
  7. 25  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  8. 28  iload_3
  9. 29  ireturn  

 

以上的过程,分析下中间码,还是可以理解的,但是非常非常让人奇怪的是,如下的代码(请还是注意不同的细节)

java 代码
  1. public class Test {         
  2.     private static int todo() {         
  3.         int b=1;         
  4.         try{         
  5.             int a=2/0;         
  6.         } catch(Exception e) {         
  7.             System.out.println("in catch");      
  8.             return b;         
  9.         } finally {  
  10.             b=3;       
  11.             System.out.println("in final");         
  12.         }         
  13.         return 2;         
  14.     }         
  15.     /**      
  16.      * @param args      
  17.      */        
  18.     public static void main(String[] args) {         
  19.         System.out.println(todo());         
  20.         
  21.     }         
  22. }        

此时运行结果照样是
in catch
in final
1

单步执行结果是 7->8->10->11->8
想不通的是,根据单步执行,在finally里对b进行了修改,但是,返回的仍旧是1

再来看看这个代码的中间码:

第三个代码的中间码
  1. 13  ldc <String "in catch"> [22]   
  2. 15  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  3. 18  iload_0 [b]   
  4. 19  istore_3   
  5. 20  iconst_3   
  6. 21  istore_0 [b]   
  7. 22  getstatic java.lang.System.out : java.io.PrintStream [16]   
  8. 25  ldc <String "in final"> [30]   
  9. 27  invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]   
  10. 30  iload_3   
  11. 31  ireturn  

因为,其实我没怎么学过汇编,只是初步的分析了
3行加载b的地址,4行在地址3储存b的值(此时地址3的值为1),5行加载一个常量,6行把常量存入b的地址(此时b的值为3),10行加载地址3的值,最后返回值。
不知道这样的解释是否合理,也请,希望能够得到一个对于try./catch块执行问题的通俗答案,谢谢!

   发表时间:2007-08-31  
参考某New版某贴:《在finally赋值为什么无效》
http://www.iteye.com/topic/79092

然后本贴可以结贴了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics