Puzzled by generics and enums
I had to write a method which, given an Enum
class, returned the set of values. First signature attempt:
public Set<Enum<?>> getValuesForEnum(Class<Enum<?>> klass);
Unfortunately this doesn’t work. When you try to invoke this method you got the error:
getValuesForEnum() can't be applied to "name.of.the.Enum"
Let’s say we have an enum named com.example.MyEnum
. The compiler complains because MyEnum.class
is not a subtype of Class<Enum<?>>
. Can you spot the error? Nested type parameters are always tricky to deal with. In this case I had to perform the following reasoning:
A<Y>
is a subtype of A<X>
if … well this never happens! For the subtype relationship to exist, wildcard must come into play, and there are no wildcards here. Except, well, there is a wildcard indeed: Enum<?>
! Unfortunately it’s in the wrong place. We have:
Class<Enum<?>>
Class<MyEnum>
To fix this problem the signature needs to be:
public Set<Enum<?>> getValuesForEnum( Class<? extends Enum<?>> klass);
Generics are invariant in Java: a List<String>
can’t be used where a List<Object>
is expected, regardless of the subtype relation between String and Object. It’s not different in this case: just that we don’t have String and Object, but Enum<?>
and Enum<MyEnum>
. There exists a subtype relation between the two arguments, but it’s irrelevant because our X
is Enum<?>
, so it’s not a wildcard.
What puzzled me is that it’s a generic type and the type argument happens to be a wildcard.