The following is not allowed in Java-8:
public interface Operator {
default String call() throws Exception {
// do some default things
return performOperation();
}
String performOperation();
}
public abstract class AbstractTestClass {
public abstract String call() throws Exception;
}
public class TestClass extends AbstractTestClass implements Operator {
@Override
public String performOperation() {
// do some operation
}
}
The above fails to compile with the error message saying that the TestClass
needs to be either abstract or override the call method.
I was thinking that the default method could provide the necessary override. Why does that not work?
I am forced to do something like the following:
public interface Operator {
default String doCall() throws Exception {
// do some default things
return performOperation();
}
String performOperation();
}
public abstract class AbstractTestClass {
public abstract String call() throws Exception;
}
public class TestClass extends AbstractTestClass implements Operator {
String call() throws Exception {
doCall();
}
@Override
public String performOperation() {
// do some operation
}
}
This is lacking the clean design that I am looking for.
I see over in this question the solution is to do:
public class TestClass extends AbstractTestClass implements Operator {
String call() throws Exception {
Operator.super.call();
}
@Override
public String performOperation() {
// do some operation
}
}
However, the solution does not explain why the compiler does not allow the above clean design. I would like to understand the reasonining and also, see if there is a way I can hide the call
method in the TestClass
.
See JLS §8.4.8.4 Inheriting Methods with Override-Equivalent Signatures:
This exception to the strict default-abstract and default-default conflict rules is made when an
abstract
method is declared in a superclass: the assertion of abstract-ness coming from the superclass hierarchy essentially trumps the default method, making the default method act as if it wereabstract
. However, theabstract
method from a class does not override the default method(s), because interfaces are still allowed to refine the signature of theabstract
method coming from the class hierarchy.
You can still use the default implementation from the method, you just have to invoke it explicitly, using InterfaceName.super.methodName()
:
public class TestClass extends AbstractTestClass implements Operator {
@Override
public String call() throws Exception {
return Operator.super.call();
}
@Override
public String performOperation() {
// do some operation
}
}
Oh, and your performOperation()
method was missing the public
keyword and the @Override
annotation.
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