java 抛出的Java抽象类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17053063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:49:32  来源:igfitidea点击:

Java abstract classes which throw

javaexceptionabstractthrow

提问by David says Reinstate Monica

If I have an abstract class with the following function -

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

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

And then another class that extends the abstract class and implements its own version of foo -

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

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

Will this create problems? Specifically in the following test case -

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

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

I did some testing and nothing seems to have broken, but I don't understand why B's foo was called and not A's

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

回答by Ravi Thapliyal

Because of Polymorphism.

因为Polymorphism.

Since, at runtime the actual object's type in the Collectionis Bso, B.foo()was called.

因为,在运行时,实际对象的类型CollectionB这样,B.foo()被调用。

Basically, if you have a sub-type objectassigned to a super-class referencethe runtime polymorphism makes sure that the sub-type's version of an instance methodgets called i.e. if it has been overriddenof course. If not, the call falls back upon the super-class version.

基本上,如果您有一个分配给超类引用的子类型对象,运行时多态性确保子类型的实例方法版本被调用,即,如果它当然已被覆盖。如果不是,则调用返回到超类版本。

What qualifies as a valid method override?

什么是有效的方法覆盖?

An overridden method must have

重写的方法必须具有

  • the same method signature
  • a covariant return type (a sub-type can be returned)
  • must not throw broader checked exceptions(applies to your question and @Dgrin91's comment i.e. just because the overridden method took some risks (threw exceptions) doesn't mean that the overriding method should do the same; so, it may not throw any exceptions at all)
  • must not use a less restrictive access modifier (can make protected to public but not private)
  • 相同的方法签名
  • 协变返回类型(可以返回子类型)
  • 不得抛出更广泛的检查异常(适用于您的问题和@Dgrin91 的评论,即仅仅因为覆盖的方法承担了一些风险(抛出异常)并不意味着覆盖的方法应该这样做;因此,它可能不会在全部)
  • 不得使用限制较少的访问修饰符(可以将保护设为公共但不设为私有)

回答by dasblinkenlight

This is not a problem - in fact, it is a common practice to throw an exception in a base class, where the functionality is not implemented, and then override the implementation with something that does not throw. Once you override a method, the method of the base class does not get called.

这不是问题 - 事实上,在基类中抛出异常是一种常见的做法,其中的功能没有实现,然后用没有抛出的东西覆盖实现。一旦你覆盖了一个方法,基类的方法就不会被调用。

One downside to this is that the users would need to catch your exception if it happens to be of a checked (as opposed to "runtime") kind. A common solution is throwing an unchecked exception.

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

Of course if the only purpose to throw an exception is indicating that the functionality is not implemented, it's best to mark the corresponding method abstract, and let Java compiler catch the possible violations.

当然,如果抛出异常的唯一目的是表明功能没有实现,那么最好标记相应的方法abstract,让Java编译器捕捉到可能的违规行为。

回答by h7r

As noted by another poster, this behaviour happens because of Polymorphism.

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

You collection was declared to be of elements of A. B, declared to extend A, is-a A. This is corroborated by the fact that you can add elements of type B to the collection (which expects instances of A).

您的集合被声明为 A.B 的元素,声明为扩展 A,是 A。您可以将 B 类型的元素添加到集合(需要 A 的实例)这一事实证实了这一点。

Your implementation of A.foo throws an exception and, if it had been called, would indeed throw it. B, on the other hand, overrides method foo, not throwing any exception. As the instances that you added to the collection was one of B, is B.foo that gets called. It changes nothing that your for loop declares the instances as being of type A (which is valid since B is-a A).

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

The behaviour you observed is the expected one.

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

For better understanding, you may want to create:

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

class C extends A {}

and add one C instance to the collection. Upon iterating C's foo will delegate to the parent class (A) and then throw an exception as expected.

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

回答by ejoncas

You can override methods without declaring throws. This is useful for callers who are using a concrete class for example someone that are using B class is not needed to try-catch cause this implementation of the method doesn't throw anything.

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

More detailed explanation is provided by Jon Skeet here: Inheritance , method signature , method overriding and throws clause

Jon Skeet 在这里提供了更详细的解释:继承、方法签名、方法覆盖和抛出子句