Lets say I have the following structure:
abstract class A {
abstract boolean foo();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
//function foo
}
Java will now complain that class C
must implement abstract method foo from A
.
I can work around this problem relatively easy by redefining the function in C
and simply calling B.super.foo();
.
however I do not understand why the default function from interface B
does not forfill this requirement on its own, and I would like to have a better understanding of the underlying mechanics of java.
At your program's current state, if you were to override A#foo
in C.java
(where the default method returns true
and the overridden method returns false
, printing C#foo
would result in false
, completely ignoring the default method.
Any abstract methods defined in an abstract class are required to be overridden by the first concrete class that extends the abstract class. For this reason, it is required that C.java
overrides A#foo
.
Default methods within interfaces are not required to be overridden.
However, both methods share identical signatures, meaning that one is required to be overridden and the other may be overridden.
This is extremely poor design and should not be used, as methods that share an identical signature cannot both be overridden. If you want to be required to override the abstract method, then simply change the name of either the abstract method, or the default method to something other than foo
.
abstract class A {
abstract boolean bar();
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
If you're looking to only override A#foo
in some cases, then you can simply remove the abstract method entirely and retain the default method within B.java
, and override it in C.java
:
abstract class A {
}
interface B {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
}
If removing A#foo
is not an option, then rename the default method, B#foo
, to something else.
abstract class A {
abstract boolean foo();
}
interface B {
default boolean bar() { return doBlah(); }
}
class C extends A implements B {
@Override
public boolean foo() {
...
}
@Override
public boolean bar() {
...
}
}
Default methods in Interfaces are used to prevent breaking programs that depend on your Interface when you add a method to your Interface.
In the case you describe, it is unclear if the default method in the interface (which by design must have been added later on) actually fulfills the contract as originally envisioned by the Abstract Class.
In this case it is safer for Java to complain.
Above text is my interpretation of the paragraph in 9.4.1.3 of the JLS SE8 spec, and I quote:
Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).
The answer of Jacob G. inspired me to come up with this solution:
interface Z {
abstract boolean foo();
}
abstract class A implements Z {
}
interface B extends Z {
default boolean foo() { return doBlah(); }
}
class C extends A implements B {
}
This way all subclasses of class A
are required to define a method foo()
, Without requiring every class that implements B
to re-implement it.
来源:https://stackoverflow.com/questions/43943553/default-interface-method-for-abstract-superclass