关于java的10个谎言之finally

经常在面试题中会看到:exit、finally、return的提问,这也是考察个人的基础知识。

一般(注意我的措辞‘一般’)我们都知道exit()是退出虚拟机,那么一旦调用了exit,则不管什么

return 、finally统统忽略不计,但前段时间看到了一篇博文“关于java的10个谎言”(搜了一下,好多

地方都有,也不知道谁是"首发"),这里要小记一下第一个问题(System.exit(0)会跳过finally的执

行?)的思考。

1、三者一般执行顺序

a、return,表示方法执行返回或者结束方法运行,其实就是方法退出栈执行

b、exit(0) ,退出虚拟机(一般认为就立马结束虚拟机生命)

c、finally ,一般直接跟在try块或者catch块后面,在try或catch语句块中控制转移语句之前执行。

eixt,很好理解,那return与finally呢?可以这样通俗的理解:

在面向对象程序执行过程其实就是各种对象之间通信,对象之间的通信不就是方法调用吗,是的,所以程序执行就是一个个方法的运行,所有方法运行完了,程序也就结束了,而finally只是一个语句,那么他势必是属于某个方法的(事实是,编译器在编译finally块的时候也只是这么做的),而return是方法的结束语句,这样一来,二者就转化为顺序执行了——先finally后return(方法都要退出栈了,还不执行finally,等待何时 ?)。

其实上面的只是帮助理解,本质上,finally块在虚拟机编译处理的时候,会将finally块的语句插入到try

或者catch语句块中的控制转移语句之前,而return就是控制转移语句之一,所以,当二者同时出现

时,finally语句块会被编译器插如到return之前 。

2、System.exit(0)会跳过finally的执行?  真的吗?

上面对三者的执行顺序做了简单总结,但是运行如下代码试试,看exit后为啥还执行finally?

public static void main(String[] args) {
        
        System.setSecurityManager(new SecurityManager(){

            @Override
            public void checkExit(int status) {
                throw new ThreadDeath();
            }
        });

        try {
            System.exit(0);
        } finally{
            System.out.println("in finally block ");
        }
    }

执行结果可能颠覆了前面说的:exit后其他都不执行,其实,前面说的是一般情况,而且99%的情况都

是那样的顺序,只是上面的代码耍了小心机(或者说我们没仔细探究exit方法)。

上面代码之所以会输出“in finally block”,是因为前面设置的SecurityManager中覆盖了checkExit方法,导致虚拟机并没有退出,为什么呢,请看分析:

其实,这一切都是因为exit方法的实现过程,以下片段为Runtime 类中exit方法源码:

 public void exit(int status) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkExit(status);
        }
        Shutdown.exit(status);
    }

main方法开始自上而下执行,首先设置了一个安全管理器实例,接着调用System.exit(0) ,调用时执行上面的exit方法,运行环境获取到了我们自定义安全管理器,并开始调用覆盖的方法,checkExit ,但checkExit方法抛出了error(不是exception,请看ThreadDeath类),导致exit的中Shutdown.exit()调用失败,从而导致虚拟机并没有退出,那么finally当然要执行了。

经此,看来我们以后在学习过程中一定要看一手资料,多看细节实现。

时间: 2024-10-12 19:13:22

关于java的10个谎言之finally的相关文章

关于Java的10个谎言

下面的这些都算是比较高级的问题了,面试中一般也很少问到,因为它们可能会把面试者拒之门外.不过你可以自己找个时间来实践一下. System.exit(0)会跳过finally块的执行 System.setSecurityManager(new SecurityManager() { @Override public void checkExit(int status) { throw new ThreadDeath(); } }); try { System.exit(0); } finally

java进阶10 GUI图形界面 布局管理器之FlowLayout GridLayout

先说说FlowLayout 流式布局管理器. 效果 这是当第一行显示不下,才转到第二行的. 看看代码 package Frame; import java.awt.BorderLayout; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.JFrame; public class MyLayout{ JFrame frame; public MyLayout(JFrame frame) { //

Eclipse调试Java的10个技巧

原文地址: http://www.oschina.net/question/82993_69439 在看这篇文章前,我推荐你看一下Eclipse 快捷键手册,我的eclipse版本是4.2 Juno. 先提三点 不要使用System.out.println作为调试工具 启用所有组件的详细的日志记录级别 使用一个日志分析器来阅读日志 1.条件断点 想象一下我们平时如何添加断点,通常的做法是双击行号的左边.在debug视图中,BreakPoint View将所有断点都列出来,但是我们可以添加一个bo

Java基础10 接口的继承与抽象类(转载)

接口继承 接口继承(inheritance)与类继承很类似,就是以被继承的interface为基础,增添新增的接口方法原型.比如,我们以Cup作为原interface: interface Cup{    void addWater(int w);    void drinkWater(int w);} 我们在继承Cup的基础上,定义一个新的有刻度的杯子的接口,MetricCup 接口如下: interface MetricCup extends Cup{    int WaterContent

几周内搞定Java的10个方法

不要将Java与JavaScript弄混了,Java的目标是“一次编译,到处调试”(呃,不对,是“到处运行”).简单来说,就是Java程序可以直接在任何设备上运行. Java语言是什么? 不管我们是否意识到,实际上我们基本每天都在与Java打交道.在浏览网页时,可能会弹出一个提示,要求必须安装Java才能继续浏览.这种情况一般发生在使用flash或者是通过某种方式将flash组件集成到核心系统的站点. Java并不是那种通常在新电脑上直接下载下来就能用的程序.我不能确定有没有操作系统将Java作

【Java二十周年】我比Java大10岁

1991年,我7岁,刚刚步入学堂不到半年.而计算机在那个年代也是一个新奇的事物.可就在那样的环境中,Java已经有了萌芽.那一年,SUN公司启动绿色计划,打算发展一种可以在任何消费电子产品上运行的软件.但由于C++自身有很多不足,所以项目组决定自行开发一种新的语言Oak.最初,Oak应用于机顶盒,但是在当时市场不成熟的情况下,项目失败了.但Oak却得到了SUN领导的赏识,于是: 1995年3月23日,在对Oak进行小规模改造后Java语言诞生了,并广泛应用于互联网领域. 一年后,在1996年,我

Java基础10:全面解读Java异常

Java基础10:全面解读Java异常 为什么要使用异常 首先我们可以明确一点就是异常的处理机制可以确保我们程序的健壮性,提高系统可用率.虽然我们不是特别喜欢看到它,但是我们不能不承认它的地位,作用. 在没有异常机制的时候我们是这样处理的:通过函数的返回值来判断是否发生了异常(这个返回值通常是已经约定好了的),调用该函数的程序负责检查并且分析返回值.虽然可以解决异常问题,但是这样做存在几个缺陷: 1. 容易混淆.如果约定返回值为-11111时表示出现异常,那么当程序最后的计算结果真的为-1111

java 24 - 10 GUI 之 四则预算的数据校验

我想要在校验的过程中,如果输入到操作数中的不是数字,则弹出提醒框: 类 JOptionPane  有助于方便地弹出要求用户提供值或向其发出通知的标准对话框 方法名 描述 showConfirmDialog 询问一个确认问题,如 yes/no/cancel. showInputDialog 提示要求某些输入. showMessageDialog 告知用户某事已发生. showOptionDialog 上述三项的大统一 (Grand Unification). 在设置窗体类添加代码: 1 priva

java 19 - 10 自定义异常的实现和测试

1 /* 2 * java不可能对所有的异常情况都考虑到,所以,在实际的开发中,我们可能需要自己定义异常. 3 * 而我们自己随意的写一个类,是不能作为异常类来看的,要想你的类是一个异常类,就必须继承自Exception或者RuntimeException 4 * 5 * 两种方式: 6 * A:继承Exception 编译期异常 7 * B:继承RuntimeException 运行期异常 8 */ 9 public class MyException extends Exception {