I have an interface A
, which class B
implements.
The following generic method works
public static <T, U extends T> List<T> listFactory(Collection<U> source) {
return new ArrayList<T>(source);
}
but
public static <T> List<T> listFactory(Collection<? extends T> source) {
return new ArrayList<T>(source);
}
does not (compilation error, type mismatch), when I am directing the output into
List<A> tester = listFactory(B.defaultCollectionFactory(3));
defaultCollectionFactory(int count)
statically provides a collection of B
s, with a default labeling scheme.
Any insights as to why that is? It seems like the generic U and wildcard are doing the same thing.
The compiler is inferring a different type parameter for the listFactory
method than you expect. It infers that T
is type B
, so the signature is effectively List<B> listFactory(Collection<? extends B> source)
. Specify the type parameter A
by being explicit in the method invocation:
List<A> tester = Test.<A> listFactory(B.defaultCollectionFactory(3));
In the first construct, you are specifying that you are returning a List
of the interface of the item that was passed in. You specify the relationship between the passed in Object and the return Object type in the U extends T
direction. In this case, the compiler can associate A
and B
with T
andU
respectively.
In the second, there is no such differentiation, so the compiler assumes that T
refers to B
and will type the return value as List<B>
. You then fall into the trap where, although B
is an instance of A
, List<B>
is not an instance of List<A>
. The compiler will complain:
Type mismatch: cannot convert from List<B> to List<A>
You will find that, with the first construct, you have the liberty of specifying a List
of any interface the B
implements or any superclass in the B
hierarchy (List<Object>
, for example), and the compiler will not complain.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With