Solution to 17b1: Default methods
A possible solution is provided via the classes and interfaces under solutions/code/tutorialquestions/question17b1/afterdefault.
-
Class
A: This class implementsI, so possible problems come from the addition of these default methods toI:default int foobar() { return bar(foo()); } default int foobar(int x) { return bar(foo(x)); }The zero-argument version of
foobaris not a problem, sinceAalready contains a method with exactly this signature. This overrides the default implementation, and the compiler is happy.However,
Aalready contained a method with the following signature:public void foobar(int x);This is a problem because it has the same argument type as the one-argument default method that has been added to
I, but a different return type. Overloading on return types is not allowed in Java, so the compiler is not happy. In the sample solution this is dealt with by renamingfoobartofoobarOriginalinA(as required by the question). -
Class
B: This class implements bothIandJ, so possible problems come from the fact that the following default methods have been added toI:default int foobar() { return bar(foo()); } default int foobar(int x) { return bar(foo(x)); }and the following to
J:default int foobar(int x) { return bar(foo(x)); }The problem is that
Bdoes not provide a method with signature:public int foobar(int x);and both
IandJprovide a default method with this signature (remember that interface methods are implicitly public). It is ambiguous which of these methodsBshould inherit, so the compiler is unhappy.The solution is to add an implementation of
foobarwith this signature toB. As explained in the question, any implementation that respects the method signature is fine; in the sample solution I have provided afoobarthat usesreturn I.super.foobar(x);to choose the default implementation offoobarcoming fromI. -
Class
C: This class implementsK, which extendsIandJ. Problems could therefore come from the default methods added byIandJ(described above), and the following default method added byK:default int foobar(int x) { return I.super.foobar(x); }The problem we had with class
B, where it was unclear whichint foobar(int x)method should be chosen given the default provided byIandJ, is not a problem here sinceKprovides the above default method of this signature, which resolves the ambiguity (by choosingI'sfoobar).However, there are two problematic methods in
C, with these signatures:public int foobar() throws IOException; protected int foobar(int x);The zero-argument
foobaris problematic because it declares that it can throw anIOException, while the default zero-argumentfoobarspecified byIdoes not claim to throw any exceptions. This is illegal: an implementing class cannot implement an interface method in a manner that throws more exceptions than the original. This would be bad because client code written against the interface would not be prepared for these additional exceptions. (Throwing fewer exceptions, in contrast, is fine.)The one-argument
foobaris problematic because it has more restricted visibility than the one-argumentfoobarspecified in each ofI,JandK. An implementing class is not allowed to decrease the visibility of an interface method that it implements, and here we have an attempt to decrease visibility from public (recall that interface methods are always public) to protected.As required by the question, the solution is to rename each of these troublesome
foobarmethods tofoobarOriginal.