继承、方法签名、方法重写和抛出子句

我的班级是:Parent

import java.io.IOException;
public class Parent {
        int x = 0;
        public int getX() throws IOException{
        if(x<=0){
         throw new IOException();
        }
       return x;
      }
 }

我这个类写一个子类:extendChild

public class Child1 extends Parent{
     public int getX(){
        return x+10;
   }
}

请注意,在重写类中的 getX 方法时,我已经从方法定义中删除了该子句。现在它会导致编译器出现异常行为,这是预期的:Childthrows

new Parent().getX() ;

不会编译而不将其包含在块中,如预期的那样。try-catch

new Child().getX() ;

编译而不将其包含在块中。try-catch

但是下面的代码行需要 try-catch 块 。

Parent p = new Child();
p.getX();

既然可以预见,即在运行时多态性期间使用父类引用来调用子方法,为什么Java的设计者没有强制要求在方法定义中包含surls子句,同时覆盖特定的父类方法?我的意思是,如果一个父类方法在其定义中有 throws 子句,那么在重写它的同时,重写方法也应该包括 throws 子句,不是吗?


答案 1

不,这是合适的 - 重写的方法可以对它抛出(和返回)的内容进行更严格的限制,因为这对于在编译时知道他们将使用被覆盖的方法并且不想打扰不可能发生的异常等的调用者非常有用。但是,它必须更具限制性而不是更宽松,这样它就不会让通过父声明访问它的调用方感到惊讶。

通过类型的引用使用重写的方法永远不会违反“它可能会抛出”的契约 - 没有异常并不违反契约。反之亦然(如果父级没有声明异常,但重写方法声明了)违反合同。ParentIOException


答案 2

好吧,重写方法可能根本不会引发任何异常(或者至少会引发更少的异常),因此您可以从 throw 子句(或整个 throw 子句)中删除异常。

假设重写方法捕获所有异常,记录它们并返回一个特殊值。尽管这不是很好的样式(它会改变方法的语义),但它仍然是可能的,因此,如果您在编译时知道您正在处理.Child

添加异常将不起作用,因为通过引用访问该类的用户不知道可能添加的任何异常。ParentChild


推荐