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?
An interface can extend other interfaces, just as a class subclass or extend another class. However, whereas a class can extend only one other class, an interface can extend any number of interfaces.
Default methods enable you to add new functionality to existing interfaces and ensure binary compatibility with code written for older versions of those interfaces. In particular, default methods enable you to add methods that accept lambda expressions as parameters to existing interfaces.
Answer is: Yes. An interface may be declared to be a direct extension of one or more other interfaces, meaning that it implicitly specifies all the member types, abstract methods, and constants of the interfaces it extends, except for any member types and constants that it may hide.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With