Skip to content
Advertisement

How to extends from generic type and override method parameter type with subclass

I have a problem with generic class hierarchy and method override. I tried to do something like below:

public class Configuration<S> {
  private List<S> elements;

  <T extends Configuration<S>> Configuration<S> merge(T anotherConfig) {
    return anotherConfig;
  }
}

and the subclass looks like:

public class ExtendedConfiguration extends Configuration<String> {

  @Override
  ExtendedConfiguration merge(ExtendedConfiguration anotherConfig) {
    return anotherConfig;
  }
}

However, subclass does not compile and I have no clue how to declare method in Configuration class so I can override it in subclass with subclass type as parameter. I want to avoid explicit casting.

Advertisement

Answer

Due to Erasure: merge in Configuration becomes:

Configuration merge(Configuration anotherConfig) {
    return anotherConfig;
}

For ExtendedConfiguration to override merge, it must have Configuration as method param type. So, below ExtendedConfiguration is fine:

class ExtendedConfiguration extends Configuration<String> {

    @Override
    Configuration<String> merge(Configuration anotherConfig) {
        return anotherConfig;
    }
}

@Override instructs the compiler to check if the method is being inherited.

With the declaration in question:

public class ExtendedConfiguration extends Configuration<String> {

  @Override
  ExtendedConfiguration merge(ExtendedConfiguration anotherConfig) {
    return anotherConfig;
  }
}

it’s overloading instead. If you remove @Override, it will compile fine.


To achieve your requirement, you can use recursive generics:

The updated declarations may look like:

Configuration

class Configuration<T extends Configuration<T, S>, S> {
    private List<S> elements;

    Configuration<T, S> merge(T anotherConfig) {
        return anotherConfig;
    }
}

ExtendedConfiguration

class ExtendedConfiguration extends Configuration<ExtendedConfiguration, String> {

    @Override
    ExtendedConfiguration merge(ExtendedConfiguration anotherConfig) {
        return anotherConfig;
    }
}

Read more here and here.

Advertisement