Java can often infer generics based on the arguments (and even on the return type, in contrast to e.g. C#).
Case in point: I've got a generic class Pair<T1, T2>
which just stores a pair of values and can be used in the following way:
Pair<String, String> pair = Pair.of("Hello", "World");
The method of
looks just like this:
public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) {
return new Pair<T1, T2>(first, second);
}
Very nice. However, this no longer works for the following use-case, which requires wildcards:
Pair<Class<?>, String> pair = Pair.of((Class<?>) List.class, "hello");
(Notice the explicit cast to make List.class
the correct type.)
The code fails with the following error (provided by Eclipse):
Type mismatch: cannot convert from
TestClass.Pair<Class<capture#1-of ?>,String>
toTestClass.Pair<Class<?>,String>
However, explicitly calling the constructor still works as expected:
Pair<Class<?>, String> pair =
new Pair<Class<?>, String>((Class<?>) List.class, "hello");
Can someone explain this behaviour? Is it by design? Is it wanted? Am I doing something wrong or did I stumble upon a flaw in the design / bug in the compiler?
Wild guess: the “capture#1-of ?” somehow seems to imply that the wildcard is filled in by the compiler on the fly, making the type a Class<List>
, and thus failing the conversion (from Pair<Class<?>, String>
to Pair<Class<List>, String>
). Is this right? Is there a way to work around this?
For completeness’ sake, here is a simplified version of the Pair
class:
public final class Pair<T1, T2> {
public final T1 first;
public final T2 second;
public Pair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public static <T1, T2> Pair<T1, T2> of(T1 first, T2 second) {
return new Pair<T1, T2>(first, second);
}
}