Java Generics – argument type and casting

Tags: ,



I have a generics problem I am trying to resolve. I’m doing some manual casting and it feels like I’m doing something wrong. I’m a bit new to using generics, so it’s very much possible I am misusing them in some capacity. Some guidance would be very much appreciated.

TLDR:
I have an interface with a generic method that takes a T argument. I’m implementing this interface in a class, but in the implementer I would like to ensure T is of a specific type (lets say Animal so I can extract some fields). How can I do that?


Details:
I have an interface Transformer below, and an implementing class where SpecialTransformer implements Transformer.

Transformer has this definition:

public interface Transformer
  public <T> Event transform(T input);

whereas SpecialTransformer has this definition:

public class SpecialTransformer implements Transformer

  @Override
  public <T> Event transform(T input) {
    Animal convertedInput = (Animal) input; // <------- This feels wrong

    String color = convertedInput.getColor();
    //Other field based logic
  

  }

Answer

Instead of putting the generics constraint on the method, you should put the constraint on the interface (and the class):

public interface Transformer<T> {
  Event transform(T input);
}

and on the class you either put a new generic type constrained to Animal and its sub-classes (or implementations):

public class SpecialTransformer<T extends Animal> implements Transformer<T> {

  @Override
  public Event transform(T input) {
    String color = input.getColor();
    //Other field based logic
  }
}

Or even plainly use Animal as the type to Transformer:

public class SpecialTransformer implements Transformer<Animal> {

  @Override
  public Event transform(Animal input) {
    String color = input.getColor();
    //Other field based logic
  }
}

You cannot achieve the same effect with the constraint on the method, because a method with signature <T> Event transform(T input) cannot be overridden by <T extends Animal> Event transform(T input), because this would be the equivalent of overriding a method transform(Object input) by transform(Animal input) which does not meet the interface contract.

On the other hand, if you expect all your Transformer implementations to accept Animal, then you could use <T extends Animal> Event transform(T input) in your interface (or public interface Transformer<T extends Animal> in my suggested form).



Source: stackoverflow