This is the old generic invariance rearing its head again.
For each call to Create
, the types are inferred as:
<String, Class<Type1>>
<String, Class<Type2>>
<String, Class<Type3>>
As you may know, a List<Dog>
is not a List<Animal>
and the same concept applies here. A Tuple2<String, Class<Type1>>
is not a Tuple2<String, Class<?>>
but it is a Tuple2<String, ? extends Class<?>>
.
So for the three inferred Tuple2
types:
Tuple2<String, Class<Type1>>
Tuple2<String, Class<Type2>>
Tuple2<String, Class<Type3>>
The type they have in common is Tuple2<String, ? extends Class<? extends Type1>>
.
As far as I know the only way around this is to supply a type witness for each call:
final List<Tuple2<String, Class<?>>> list = Arrays.asList(
Tuple2.<String, Class<?>>Create("1", Type1.class),
Tuple2.<String, Class<?>>Create("2", Type2.class),
Tuple2.<String, Class<?>>Create("3", Type3.class)
);
That should work.
It seems like this should work:
final List<Tuple2<String, Class<?>>> list = Arrays.asList(
Tuple2.Create("1", (Class<?>)Type1.class),
Tuple2.Create("2", (Class<?>)Type2.class),
Tuple2.Create("3", (Class<?>)Type3.class)
);
But it doesn't compile. The compiler does capture conversion and infers the Class<?>
as Class<capture of ?>
. So the inferred types you end up with are something like:
<String, Class<capture #1 of ?>>
<String, Class<capture #2 of ?>>
<String, Class<capture #3 of ?>>
And still three distinct types from each other.
I will be honest: I have no idea why it works that way, just that it does. I have been unable to find a definitive answer to that. The spec says this:
- If Ti is a wildcard type argument [...] of the form ?, then Si is a fresh type variable [...].
Which seems to imply that capture of ?
is considered as a new type and distinct from ?
.
It seems to me that inference just has a gap with respect to the wildcard as of version 7.