Search code examples
javagenericsinheritancefunctional-interface

Overriding method that returns and consumes a generic class with sub-interfaces


I want to make a generic interface that has two abstract methods, and one of them returns and consumes sub-type with same generic type of the interface.

The goal I want to achieve is that creating @FunctionalInterfaces having same parents, but different way of composing themselves.

My first approach is as below,

public interface ParentFunction<T, C extends ParentFunction> {

  void doSomething(T t);

  C<T> compose(C<T> other);
}

@FunctionalInterface
public interface SonFunction<T> extends ParentFunction<T, SonFunction> {

  @Override
  default SonFunction<T> compose(SonFunction<T> other){
    return null;
  }
}

@FunctionalInterface
public interface SonFunction<T> extends ParentFunction<T, SonFunction> {

  @Override
  default DaughterFunction<T> compose(SonFunction<T> other){
    return null;
  }
}

But an compile error occurs at C<T> of parent method saying, 'Type "C" does not have type parameters,' and another at @Override of child default method.

I can just separate my child interfaces without extending, but I hope them to have an super-type that the client code will only knows.

Is there any cool technique that I may use to achieve it?


Solution

  • In Java, you cannot do C<T>, however, you can require C to extend ParentFunction<T,C>

    Same applies to your SonFunction and DaughterFunction.

    Try this:

    public interface ParentFunction<T, C extends ParentFunction<T, C>> {
        void doSomething(T t);
        C compose(C other);
    }
    
    @FunctionalInterface
    public interface SonFunction<T> extends ParentFunction<T, SonFunction<T>> {
    
        @Override
        default SonFunction<T> compose(SonFunction<T> other){
            return null;
        }
    }
    
    @FunctionalInterface
    public interface DaughterFunction<T> extends ParentFunction<T, DaughterFunction<T>> {
    
        @Override
        default DaughterFunction<T> compose(DaughterFunction<T> other){
            return null;
        }
    }