Java generics end of mystery

1 minute read

Remember my puzzlement in front of

I usually try to make sense of the unknown type by looking at what should be allowed when two incompatible types are used as the unknown type, and then using the generic type using the unknown type as a reference to a known type to see what incorrect things can be done through the reference. If the assignment your questioning was allowed, you would be able to add two incompatible ConstraintValidators to the validatedAddresses as in:

class Address {}
class Person {}

// A set of ConstraintValidator for Address
Set<ConstraintValidator<Address>> validatedAddresses =
    new HashSet<ConstraintValidator<Address>>();

// A set of ConstraintValidator of a single unknown type (*)
Set<ConstraintValidator<?>> validatedThings = validatedAddresses;

ConstraintValidator<Address> a;
ConstraintValidator<Person> p;

// A ConstraintValidator of unknown type, ? = Address
ConstraintValidator<?> thingA = a;

// A ConstraintValidator of unknown type, ? = Person
ConstraintValidator<?> thingP = p;

// This would be allowed if (*) was a valid assignment, which puts a ConstraintValidator<Person> in a set of ConstraintValidator<Address>


What I missed initially is that I cannot add new (and potentially heterogeneous) elements in Set<?> or Set<? extends X>, but I am free to add elements in Set<X<?>>:

Set<A<?>> c1 = new HashSet<A<?>>();
c1.add( new A<B>() );
c1.add( new A<C>() );

Set<? extends A<?>> c1 = new HashSet<A<?>>();
c1.add( new A<B>() ); <-- compilation error
c1.add( new A<C>() ); <-- compilation error

While the first example compiles, the second does not.

So to answer my initial mystery, I need to use the <? extends X<?>> approach (thanks Vivien for pointing that out).

Set<? extends ConstraintValidator<?>> valiatedThings = ...;