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

时间:2012-01-27 15:47:30

标签: java inheritance polymorphism override 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;
   }
}

请注意,当{em>覆盖 Child类中的 getX 方法时,我已从方法定义中删除了throws子句。现在结果如下在预期的编译器的异常行为中:

new Parent().getX() ;
如果不按预期将

包含在try-catch块中,

就不会编译。

new Child().getX() ;

编译时不将其括在try-catch块中。

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

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

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

4 个答案:

答案 0 :(得分:32)

不,这是合适的 - 重写的方法可以对它抛出(和返回)的内容有更多的限制,因为这对于在编译时知道的调用者他们将使用重写方法,并且不想打扰不会发生的异常等。它必须更具限制性而不是更多许可,因此它不会让那些的呼叫者感到惊讶通过父声明访问它。

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

答案 1 :(得分:3)

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

假设重写方法捕获所有异常,记录它们并返回特殊值。虽然这不是好的样式(它会改变方法的语义),但它仍然是可能的,因此如果你在编译时知道你正在处理{{1},你就不必捕获永远不会抛出的异常。 }。

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

答案 2 :(得分: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中

,那么它将导致编译错误。

答案 3 :(得分:2)

易于记忆

  1. 访问修饰符可以从限制更改为限制更少,
    例如,从受保护到公共,但反之亦然
  2. throws签名可以是父异常更改为子异常类,但反之亦然
  3. 此代码有效

    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的子代

    顺便说一句,你可以从超类覆盖方法而不是在所有

    中抛出ecxeptions

    此代码有效

    public class A  {
    
        public String foo() throws IOException{
            return "a";
        }
    
        class B extends A {
            @Override
            public String foo(){
                return "b";
            }
        }
    }