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 }
Advertisement
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).