Solution to 74d2: Exceptions and inheritance (i)
See code at solutions/code/tutorialquestions/question74d2
Classes A
and B
do compile. The potential reason for which I was hoping you might have
thought they would not compile was the fact that A
declares a method foo
with the following signature:
public void foo() throws Exception;
while B
attempts to override foo
with a different signature:
@Override
public void foo();
The difference is that foo
in A
throws Exception
while foo
in B
does not throw any exception. This is OK, however: it is permissible for an overridden method to throw a narrower type of exception than the exception specified in the superclass, or
(as in this case) to throw no exception at all.
The way to think about this is that it is OK for the overridden method to behave better than the superclass method. Client code that uses the superclass must be prepared to deal with any exceptions the superclass method may throw. If at runtime an instance of the subclass, whose method behaves better, is present, this is no problem. (Do you see why the rule therefore could not be the other way around? I.e., why wouldn't it make sense to allow subclass methods to throw more, or more general exceptions than the superclass specifies?)
Changing to body of foo
in B
from:
@Override
public void foo() {
}
to:
@Override
public void foo() {
super.foo();
}
leads to a compilation error. The reason is that super.foo();
requests that method foo
in A
is called. However, this method may throw an Exception
, which foo
in B
would have to deal with, but does not.
This problem can be solved either by changing foo
in B
to throw Exception
, so that if foo
in A
does throw an Exception
this is propagated by foo
in B
, or by enclosing the call to super.foo();
in a try...catch
block:
@Override
public void foo() {
try {
super.foo();
} catch(Exception e) {
// Do something
}
}