问题
In the SCJP book by Kathey Sierra, an excerpt is as follows:
If a method is overridden but you use a polymorphic (supertype) reference to refer to the subtype object with the overriding method, the compiler assumes you’re calling the supertype version of the method. If the supertype version declares a checked exception, but the overriding subtype method does not, the compiler still thinks you are calling a method that declares an exception (more in Chapter 5).
Let’s take a look at an example:
class Animal { public void eat() throws Exception { // throws an Exception } } class Dog2 extends Animal { public void eat() { /* no Exceptions */ } public static void main(String[] args) { Animal a = new Dog2(); Dog2 d = new Dog2(); d.eat(); // ok a.eat(); // compiler error - // unreported exception } }
This code will not compile because of the Exception declared on the Animal eat() method. This happens even though, at runtime, the eat() method used would be the Dog version, which does not declare the exception.
Now what I don't understand is that how come a.eat();
raises a compiler error?
(overridden function in child may not have any Exception even when Super does)
回答1:
The compiler doesn't know the real type of the object referenced. It only checks that assignments are valid.
The call to a.eat
causes a compile error because the compiler doesn't know the Animal referenced by a is a Dog2. It is deciding whether a checked exception can be thrown based solely on the type of the variable referencing the Dog2.
The compiler is not smart. It does not run the code and it does not keep track of the actual class of the object assigned to the variable a
.
Just as when you refer to an object with the type of its superclass you won't see methods specific to the subclass, you also see the throws-clause of the superclass, not that of the subclass's method.
If you add a cast to the subclass in the last line:
((Dog2)a).eat();
then you won't get the unreported exception compile error.
回答2:
When you look at the code, you can realize: when the object you invoke eat() on is
- a Dog, then the call will not throw an exception
- an Animal, then that call could throw
Because of that, the second usage results in the compiler complaining to you.
Overriding a method and to reduce the throws signature is perfectly fine. A caller that knows how to deal with an exception for sure works when a sub class never throws.
来源:https://stackoverflow.com/questions/40954791/scjp-override-method-with-exception-handling-raises-a-compiler-error