Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default method implementation to override abstract method

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.

like image 759
arin Avatar asked Dec 15 '16 18:12

arin


1 Answers

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 were abstract. However, the abstract method from a class does not override the default method(s), because interfaces are still allowed to refine the signature of the abstract 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.

like image 124
Andreas Avatar answered Oct 02 '22 23:10

Andreas