Java抛出的抽象类

时间:2013-06-11 20:22:03

标签: java exception abstract throw

如果我有一个具有以下功能的抽象类 -

abstract class A{
    void foo(String s) throws Exception{
        throw new Exception("exception!");
    }
}

然后是另一个扩展抽象类并实现自己的foo版本的类 -

class B extends A{
    void foo(String s){
        //do stuff that does *not* throw an exception
    }
}

这会产生问题吗?具体在以下测试用例中 -

Collection<A> col = new Collection<A>();
B b = new B();
col.add(b);
for(A a : col){
    a.foo();
}

我做了一些测试,似乎没有什么破坏,但我不明白为什么B的foo被调用而不是A的

4 个答案:

答案 0 :(得分:11)

由于Polymorphism

因为在运行时Collection中的实际对象类型是B所以,B.foo()被调用了。

基本上,如果您将子类型对象分配给超类引用,则运行时多态性可确保子类型的 < em>一个实例方法 被调用,即它当然是 重写 。如果没有,则呼叫将回退到超级版本。

什么是合格的有效方法覆盖?

重写方法必须

  • 相同的方法签名
  • 协变返回类型(可以返回子类型)
  • 不得抛出更广泛的已检查异常 (适用于您的问题和@ Dgrin91的评论,即仅因为被覆盖的方法带来了一些风险(抛出异常)并非如此t表示重写方法应该这样做;因此,它可能不会抛出任何异常)
  • 不得使用限制较少的访问修饰符(可以保护公开但不保密)

答案 1 :(得分:3)

这不是问题 - 实际上,在基类中抛出异常是常见的做法,其中未实现功能,然后使用不抛出的内容覆盖实现。覆盖方法后,不会调用基类的方法。

这样做的一个缺点是,如果用户恰好是检查(而不是“运行时”)类型,则需要捕获异常。一个常见的解决方案是抛出未经检查的异常。

当然,如果抛出异常的唯一目的是指示未实现该功能,则最好标记相应的方法abstract,并让Java编译器捕获可能的违规。

答案 2 :(得分:0)

正如另一张海报所指出的,这种行为是因为多态性而发生的。

您的集合被声明为A. B的元素,声明为扩展A,是-A A.这可以通过以下事实证实:您可以向集合中添加类型B的元素(期望A的实例)

A.foo的实现会抛出异常,如果它被调用,确实会抛出异常。另一方面,B覆盖方法foo,而不是抛出任何异常。由于您添加到集合中的实例是B之一,因此被调用的是B.foo。它不会改变你的for循环将实例声明为类型A(由于B是-A A,因此有效)。

您观察到的行为是预期的行为。

为了更好地理解,您可能想要创建:

class C extends A {}

并向集合中添加一个C实例。迭代C的foo将委托给父类(A),然后按预期抛出异常。

答案 3 :(得分:0)

您可以在不声明抛出的情况下覆盖方法。这对于使用具体类的调用者很有用,例如某些使用B类的人不需要try-catch,因为该方法的实现不会抛出任何东西。

Jon Skeet在此提供了更详细的解释:Inheritance , method signature , method overriding and throws clause