按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
System。out。println(
〃Throwing MyException from g()〃);
throw new MyException(〃Originated in g()〃);
}
public static void main(String'' args) {
try {
271
…………………………………………………………Page 273……………………………………………………………
f();
} catch(MyException e) {
e。printStackTrace();
}
try {
g();
} catch(MyException e) {
e。printStackTrace();
}
}
} ///:~
继承在创建新类时发生:
class MyException extends Exception {
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
这里的关键是“extends Exception”,它的意思是:除包括一个Exception 的全部含义以外,还有更多的含
义。增加的代码数量非常少——实际只添加了两个构建器,对 MyException 的创建方式进行了定义。请记
住,假如我们不明确调用一个基础类构建器,编译器会自动调用基础类默认构建器。在第二个构建器中,通
过使用 super 关键字,明确调用了带有一个 String 参数的基础类构建器。
该程序输出结果如下:
Throwing MyException from f()
MyException
at Inheriting。f(Inheriting。java:16)
at Inheriting。main(Inheriting。java:24)
Throwing MyException from g()
MyException: Originated in g()
at Inheriting。g(Inheriting。java:20)
at Inheriting。main(Inheriting。java:29)
可以看到,在从f() “掷”出的MyException 违例中,缺乏详细的消息。
创建自己的违例时,还可以采取更多的操作。我们可添加额外的构建器及成员:
//: Inheriting2。java
// Inheriting your own exceptions
class MyException2 extends Exception {
public MyException2() {}
public MyException2(String msg) {
super(msg);
}
public MyException2(String msg; int x) {
super(msg);
i = x;
}
public int val() { return i; }
272
…………………………………………………………Page 274……………………………………………………………
private int i;
}
public class Inheriting2 {
public static void f() throws MyException2 {
System。out。println(
〃Throwing MyException2 from f()〃);
throw new MyException2();
}
public static void g() throws MyException2 {
System。out。println(
〃Throwing MyException2 from g()〃);
throw new MyException2(〃Originated in g()〃);
}
public static void h() throws MyException2 {
System。out。println(
〃Throwing MyException2 from h()〃);
throw new MyException2(
〃Originated in h()〃; 47);
}
public static void main(String'' args) {
try {
f();
} catch(MyException2 e) {
e。printStackTrace();
}
try {
g();
} catch(MyException2 e) {
e。printStackTrace();
}
try {
h();
} catch(MyException2 e) {
e。printStackTrace();
System。out。println(〃e。val() = 〃 + e。val());
}
}
} ///:~
此时添加了一个数据成员 i;同时添加了一个特殊的方法,用它读取那个值;也添加了一个额外的构建器,
用它设置那个值。输出结果如下:
Throwing MyException2 from f()
MyException2
at Inheriting2。f(Inheriting2。java:22)
at Inheriting2。main(Inheriting2。java:34)
Throwing MyException2 from g()
MyException2: Originated in g()
at Inheriting2。g(Inheriting2。java:26)
at Inheriting2。main(Inheriting2。java:39)
Throwing MyException2 from h()
273
…………………………………………………………Page 275……………………………………………………………
MyException2: Originated in h()
at Inheriting2。h(Inheriting2。java:30)
at Inheriting2。main(Inheriting2。java:44)
e。val() = 47
由于违例不过是另一种形式的对象,所以可以继续这个进程,进一步增强违例类的能力。但要注意,对使用
自己这个包的客户程序员来说,他们可能错过所有这些增强。因为他们可能只是简单地寻找准备生成的违
例,除此以外不做任何事情——这是大多数 Java 库违例的标准用法。若出现这种情况,有可能创建一个新违
例类型,其中几乎不包含任何代码:
//: SimpleException。java
class SimpleException extends Exception {
} ///:~
它要依赖编译器来创建默认构建器(会自动调用基础类的默认构建器)。当然,在这种情况下,我们不会得
到一个SimpleException(String)构建器,但它实际上也不会经常用到。
9。5 违例的限制
覆盖一个方法时,只能产生已在方法的基础类版本中定义的违例。这是一个重要的限制,因为它意味着与基
础类协同工作的代码也会自动应用于从基础类衍生的任何对象(当然,这属于基本的 OOP 概念),其中包括
违例。
下面这个例子演示了强加在违例身上的限制类型(在编译期):
//: StormyInning。java
// Overridden methods may throw only the
// exceptions specified in their base…class
// versions; or exceptions derived from the
// base…class exceptions。
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
abstract class Inning {
Inning() throws BaseballException {}
void event () throws BaseballException {
// Doesn't actually have to throw anything
}
abstract void atBat() throws Strike; Foul;
void walk() {} // Throws nothing
}
class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}
interface Storm {
void event() throws RainedOut;
void rainHard() throws RainedOut;
}
public class StormyInning extends Inning
implements Storm {
// OK to add new exceptions for constructors;
274
…………………………………………………………Page 276……………………………………………………………
// but you must deal with the base constructor
// exceptions:
StormyInning() throws RainedOut;
BaseballException {}
StormyInning(String s) throws Foul;
BaseballException {}
// Regular methods must conform to base class:
//! void walk() throws PopFoul {} //pile error
// Interface CANNOT add exceptions to existing
// methods from the base class:
//! public void event() throws RainedOut {}
// If the method doesn't already exist in the
// base class; the exception is OK:
public void rainHard() throws RainedOut {}
// You can choose to not throw any exceptions;
// even if base version does:
public void event() {}
// Overridden methods can throw
// inherited exceptions:
void atBat() throws PopFoul {}
public static void main(String'' args) {
try {
StormyInning si = new StormyInning();
si。atBat();
} catch(PopFoul e) {
} catch(RainedOut e) {
} catch(BaseballException e) {}
// Strike not thrown in derived version。
try {
// What happens if you upcast?
Inning i = new StormyInning();
i。atBat();
// You must catch the exceptions from the
// base…class version of the method:
} catch(Strike e) {
} catch(Foul e) {
} catch(RainedOut e) {
} catch(BaseballException e) {}
}
} ///:~
在 Inning 中,可以看到无论构建器还是event()方法都指出自己会“掷”出一个违例,但它们实际上没有那
样做。这是合法的,因为它允许我们强迫用户捕获可能在覆盖过的event()版本里添加的任何违例。同样的
道理也适用于abstract 方法,就象在 atBat()里展示的那样。
“interface Storm”非常有趣,因为它包含了在 Ining 中定义的一个方法——event(),以及不是在其中
定义的一个方法。这两个方法都会“掷”出一个新的违例类型:RainedOut。当执行到“StormyInning
extends”和“implements Storm”的时候,可以看到Storm 中的event()方法不能改变 Inning中的event()
的违例接口。同样地,这种设�