Reputation: 37655
Suppose there are two interfaces Interface1
and Interface2
where Interface2
extends Interface1
.
interface Interface1 {
default void method() {
System.out.println("1");
}
// Other methods
}
interface Interface2 extends Interface1 {
@Override
default void method() {
System.out.println("2");
}
// Other methods
}
Suppose I want to create a class that implements Interface2
but I want method()
to be the version in Interface1
. If I write
class MyClass implements Interface1, Interface2 {
public void method() {
Interface1.super.method();
}
}
I get the compilation error:
bad type qualifier in default super call: redundant interface Interface1 is extended by Interface2
It is possible to get around this by creating a third interface:
interface Interface3 extends Interface1 {
default void method() {
Interface1.super.method();
}
}
Then:
class MyClass implements Interface1, Interface2, Interface3 {
public void method() {
Interface3.super.method();
}
}
This compiles fine, and if I instantiate a new MyClass
and invoke method()
, the output is 1
as expected.
So my question is, given that it is so easy to get around the restriction that you can only write InterfaceName.super.method()
for the most specific interface in a chain, what is the reason for the restriction? What problems are prevented by disallowing you from writing Interface1.super.method()
in the first place?
Upvotes: 32
Views: 4129
Reputation: 37875
This is exactly addressed by the JLS in 15.12.3. "Compile-Time Step 3: Is the Chosen Method Appropriate?".
If the form is TypeName . super . [TypeArguments] Identifier, then:
- […]
- If TypeName denotes an interface, let
T
be the type declaration immediately enclosing the method invocation. A compile-time error occurs if there exists a method, distinct from the compile-time declaration, that overrides (§9.4.1) the compile-time declaration from a direct superclass or direct superinterface ofT
.
The JLS goes on to explain why the rule is in place:
In the case that a superinterface overrides a method declared in a grandparent interface, this rule prevents the child interface from "skipping" the override by simply adding the grandparent to its list of direct superinterfaces. The appropriate way to access functionality of a grandparent is through the direct superinterface, and only if that interface chooses to expose the desired behavior.
So it more or less exists specifically to stop you from doing what you're trying to do.
But the JLS also seems to acknowledge your workaround:
(Alternately, the developer is free to define his own additional superinterface that exposes the desired behavior with a super method invocation.)
Upvotes: 18