我的Parent
类是:
import java.io.IOException;
public class Parent {
int x = 0;
public int getX() throws IOException{
if(x<=0){
throw new IOException();
}
return x;
}
}
我用extend
这个类写一个子类Child
:
public class Child1 extends Parent{
public int getX(){
return x+10;
}
}
注意,当重写Child
类中的getX方法时,我已经从方法定义中删除了throws
子句。现在,它导致编译器出现异常行为,这是意料之中的:
new Parent().getX() ;
如果不将其封装在try-catch
块中,则不会进行编译。
new Child().getX() ;
编译而不将其封装在CCD_ 7块中。
但是下面的代码行需要try-catch块。
Parent p = new Child();
p.getX();
由于这是可以预见的,即在运行时多态性期间使用父类引用来调用子方法,为什么Java的设计者没有强制在方法定义中包括throws子句,同时覆盖特定的父类方法?我的意思是,如果父类方法的定义中有throws子句,那么在重写它的同时,重写方法也应该包括throws子句。不是吗?
不,这是合适的-重写的方法可以对它抛出(和返回)的内容有更严格的限制,因为这对那些在编译时知道他们将使用重写的方法,并且不想为不可能发生的异常而烦恼的调用方很有用,这样就不会让通过父声明访问它的调用者感到惊讶。
通过Parent
类型的引用使用重写的方法永远不会违反"它可能抛出IOException
"的约定——没有异常并不违反约定。反过来(如果父没有声明异常,但重写方法声明了)将违反合同。
好吧,重写方法可能根本不会抛出任何异常(或者至少不会抛出更少的异常),因此您可以从throw子句(或整个throw子句)中删除异常。
假设重写方法捕获所有异常,记录它们并返回一个特殊值。尽管这不是一种好的风格(它会改变方法的语义),但它仍然是可能的,因此,如果您在编译时知道您正在处理Child
,则不必捕获从未抛出的异常。
添加异常是不起作用的,因为通过Parent
引用访问该类的用户不知道Child
可能添加的任何异常。
易于记忆的
- 访问修饰符可以从限制更改为限制较少,
例如,从受保护的到公共的,但不是从受保护到公共的 - throws签名可以是从父异常到子异常类的更改,但不能反过来
此代码是有效的
public class A {
protected String foo() throws Exception{
return "a";
}
class B extends A {
@Override
public String foo() throws IOException{
return "b";
}
}
}
重写的foo方法具有公共访问权限,不受保护,并抛出Exception 的子级IOException
此代码不是有效的
public class A {
public String foo() throws IOException{
return "a";
}
class B extends A {
@Override
protected String foo() throws Exception{
return "b";
}
}
}
重写的foo方法具有更受限制的访问修饰符,并抛出Exception that NOT IOException 的子级
顺便说一句,你可以覆盖超类中的方法,而不是在所有中抛出ecxeptions
此代码有效
public class A {
public String foo() throws IOException{
return "a";
}
class B extends A {
@Override
public String foo(){
return "b";
}
}
}
您可以自由地重写不带throws关键字的方法,因为如果您想通过控制所有异常来开发方法,那么您可以通过重写不带任何throws子句的方法来实现这一点。
但请记住,如果你想在子类方法中包括throws子句,那么throws子句必须与必须相同的异常相关联,或者与它的超类方法抛出的异常的子类相关联。例如
class Super{
void a()throws IOException{
......
}
}
class Sub extends Super{
void a()throws IOException{
......
}
}
Sub类的a()方法必须抛出IOException或IOException的任何子类,否则编译器将显示错误。
这意味着如果你写
void a()throws Exception
在Sub类中,则会导致编译错误。