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



我的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可能添加的任何异常。

易于记忆的

  1. 访问修饰符可以从限制更改为限制较少,
    例如,从受保护的到公共的,但不是从受保护到公共的
  2. 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类中,则会导致编译错误。

相关内容

最新更新