19

我的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;
   }
}

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

new Parent().getX() ;

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

new Child().getX() ;

编译时不将其封闭在一个try-catch块中。

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

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

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

4

4 回答 4

35

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

通过类型的引用使用覆盖的方法Parent永远不会违反“它可能抛出IOException”的合同——没有异常不会违反合同。反过来(如果父级没有声明异常,但覆盖方法声明)违反合同。

于 2012-01-27T15:50:41.080 回答
3

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

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

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

于 2012-01-27T15:51:07.453 回答
3

容易记住

  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 方法具有公共访问权限,不受保护并抛出 IOException 异常的孩子

此代码无效

public class A  {

    public String foo() throws IOException{
        return "a";
    }

    class B extends A {
        @Override
        protected String foo() throws Exception{
            return "b";
        }
    }
}

重写的 foo 方法具有更多受限的访问修饰符并抛出不是 IOException 子级的异常

顺便说一句,您可以覆盖超类中的方法并且根本不抛出异常

此代码有效

public class A  {

    public String foo() throws IOException{
        return "a";
    }

    class B extends A {
        @Override
        public String foo(){
            return "b";
        }
    }
}
于 2015-07-07T20:03:26.803 回答
2

您可以自由地重写不带 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 类中,则会导致编译错误。

于 2012-01-28T05:49:04.180 回答