Java异常系列第三集——多态中的异常

本博客为个人原创,转载需在明显位置注明出处

多态在实际项目开发中是经常用到的一个概念,那么多态中的异常是怎样的呢?下面我们就来讨论一下,为了节省时间,我直接用了《Thinking in Java》中的栗子(由于是多态,肯定有一系列的继承关系,所以代码较多,请仔细阅读):

class BaseballException extends Exception {
}

class Foul extends BaseballException {
}

class Strike extends BaseballException {
}

首先是三个自定义异常类,Foul和Strike均是BaseballException的子类

abstract class Inning {

    public Inning() throws BaseballException {
    }
    
    public Inning(String s) {
    }

    public void event() throws BaseballException {
    }

    public void walk() {
    }

    public abstract void atBat() throws Strike, Foul;

}

接下来是一个抽象类,其中atBat()是抽象方法,注意每个方法抛出的异常,下面会有逐个总结和解释

class StormException extends Exception {
}

class RainedOut extends StormException {
}

class PopFoul extends Foul {
}

又是三个自定义异常,注意,RainedOut是刚刚定义的StormException的子类,PopFoul是上面定义的Foul的子类

interface Storm {
    public void event() throws RainedOut;

    public void rainHard() throws RainedOut;
}

擦,还有一个接口,感觉整个人都不好了,在坚持一下,马上就到最后了。注意一下,接口里面有一个event()方法,上面抽象类Inning也有一个event()方法,只是抛出的异常不同

class StormyInning extends Inning implements Storm {

    public StormyInning() throws RainedOut, BaseballException {
        // 构造方法必须throws父类构造方法的Exception
        // 子类构造方法调用super,不可捕获父类的异常
    }

    public StormyInning(String s) {
        super("");
    }

    @Override
    public void event() {
        // 父类event方法和接口event方法抛出的异常不一致,所以只能重写方法,不抛出任何异常
    }

    @Override
    public void rainHard() {
        // 子类重写方法,可以将抛出的异常范围缩小或者不抛出异常
    }

    @Override
    public void atBat() throws PopFoul {
        // 子类重写方法,可以抛出父类抛出异常的子类异常
        // PopFoul extends Foul
    }

    // @Override
    // public void walk() throws StormException {
        // 如果父类方法未抛出异常,子类重写方法不可抛出异常
    // }
}

终于结束了,最后一个实现类StormInning,集成抽象类Inning,实现接口Storm,内部重写了一些方法,下面我们就挨个总结:

重写方法###

1.父类方法不throws异常,子类重写方法不可throws

看代码中的walk方法,父类Inning中walk方法是没有抛出异常的,但是在子类StormInning中重写并且添加异常说明,编译不通过的。回顾一下多态的概念,简单来说就是父类引用指向子类对象,试想一下,父类方法中没有抛出异常,子类却抛出了异常,假设可以编译通过,那么父类的引用去调用这个方法时,是不需要捕获异常的,但是真正执行的是子类中重写的方法,只要子类方法中出现问题抛出异常,结果都是致命的

2.子类重写方法可以缩小异常范围或不throws异常

这一点跟1恰恰相反,看rainedOut方法,在接口中添加了异常说明,但是重写时去掉了异常说明。这个是可行的,因为无论怎样,父类引用在调用rainedOut方法时都会提示要捕获异常,子类重写方法中不抛异常没问题,抛了异常也可以捕获到。

3.子类重写方法可throws父类异常的子类

看下代码中的atBat方法,父类Inning中定义抛出的是Foul异常,子类重写时抛出了Foul的子类PopFoul异常,这个也是ok的。关于这点可以参考上一篇文章中的异常匹配部分,捕获异常的时候,父类异常是可以匹配子类异常的。

4.父类和接口包含同一方法,但定义抛出的异常不同,子类只能重写方法并且不可throws任何异常

Inning类和Storm接口都有一个相同的event方法,区别只是抛出的异常类型不同,一个抛出BaseballException异常,另一个是RainedOut异常,我们在子类StormInning中重写该方法时,若只抛出BaseballException,那么不匹配接口中的定义,若只抛出RainedOut,就不匹配父类中的定义,两个异常都抛出,父类和接口都不匹配,真是里外都不是人。所以这种情况下,重写方法时不能抛出任何异常,正好符合上述总结2。

构造方法###

1.子类构造方法可以扩大异常范围

与重写方法只能缩小异常范围相反,子类构造方法是可以扩大异常范围的,为什么?《Thinking in java》中只有结论没有做任何解释,说说我的理解:还是多态的概念,父类引用在指向具体的对象时,需要new出具体的类对象,子类对象和父类对象是不一样的,而在调用方法时父类与子类就没有区分,方法名都是一致的,只是在运行时执行的地方不一样。那么子类构造方法中扩大异常范围,增加一些其他异常的抛出,完全不会影响调用方的异常捕获。可以参考代码中StormInning类的无参构造方法,比父类多抛出了RainedOut异常

2.如果子类构造方法调用了父类的有异常抛出的构造方法,必须throws父类构造方法的异常,该异常不可再子类中捕获

还是StormInning的无参构造方法,若是删除BaseballException的异常说明,编译器就会报错,为什么?因为虽然没有显示调用,但是StormInning的无参构造方法实际上调用了父类的默认构造方法,而父类Inning的默认构造方法有异常抛出,所以子类必须抛出这个异常。或许你会说,我完全可以在子类构造方法中调用一下super(),然后try-catch,这样子类就不需要抛出异常了。一开始我也以为可以,实际上却不行,因为我们是无法在子类捕获父类构造方法抛出的异常的,必须抛出,至于为什么,我也不是太清楚,有知道的盆友还请不吝赐教。

3.父类引用和子类引用在调用方法时,捕获的异常可能不同

这有个前提条件就是父类方法和子类方法抛出的异常要不同才行,就拿atBat方法为例:

@Test
public void testPolymophism() {
    try {
        StormyInning sinn = new StormyInning();
        sinn.atBat();
    } catch (PopFoul e) {
        e.printStackTrace();
    } catch (RainedOut e) {
        e.printStackTrace();
    } catch (BaseballException e) {
        e.printStackTrace();
    }

    try {
        Inning inn = new StormyInning();
        inn.atBat();
    } catch (Strike e) {
        e.printStackTrace();
    } catch (Foul e) {
        e.printStackTrace();
    } catch (RainedOut e) {
        e.printStackTrace();
    } catch (BaseballException e) {
        e.printStackTrace();
    }       
}

首先构造方法抛出的异常是一致的,atBat在子类重写时修改了抛出异常的类型为Foul的子类,所以子类引用在调用时,只需要捕获PopFoul异常即可;而父类引用在调用时就必须捕获父类方法定义的两个Strike和Foul异常。

好了,关于异常的基本技术细节就介绍到这里,很少写这种纯理论的东西,看着让人昏昏欲睡,但是语言基础就是这么枯燥,想成为一名优秀的程序员,你必须克服!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,505评论 18 399
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,030评论 0 62
  • 两类异常 Java中的异常继承体系为: 这里的异常( Exception)分为两大类:Checked异常和Runt...
    tobe_superman阅读 631评论 0 0
  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 1,936评论 0 3
  • “我错啦”! 她跪在地上声嘶力竭的说,准确点应该是喊。我牙根没看到丁点的歉意,更多的是在逼迫下的无奈...
    老魁_河北阅读 348评论 3 1