While f1 does compile, the very similar f2 won’t and I just cant explain why.
(Tested on Intellij 9 and Eclipse 3.6)
And really I thought I was done with that kind of question.
import java.util.*;
public class Demo {
public List<? extends Set<Integer>> f1(){
final List<HashSet<Integer>> list = null;
return list;
}
public List<List<? extends Set<Integer>>> f2(){
final List<List<HashSet<Integer>>> list = null;
return list;
}
}
List<List<HashSet<Integer>>>is not assignable toList<List<? extends Set<Integer>>>for the same reasonList<HashSet<Integer>>would not be assignable toList<Set<Integer>>.You can get it to compile by changing this:
into this:
The reason your code didn’t compile, and why the other example I gave (ie: “
List<HashSet<Integer>>would not be assignable toList<Set<Integer>>“) is that Java generics are not covariant.The canonical example is that even if
CircleextendsShape,List<Circle>does not extendList<Shape>. If it did, thenList<Circle>would need to have anadd(Shape)method that acceptsSquareobjects, but obviously you don’t want to be able to addSquareobjects to aList<Circle>.When you use a wildcard, you’re getting a type that slices away certain methods.
List<? extends Shape>retains the methods that returnE, but it doesn’t have any of the methods that takeEas a parameter. This means you still have theE get(int)method, butadd(E)is gone.List<? extends Shape>is a super-type ofList<Shape>as well asList<Circle>,List<? extends Circle>, etc. (? superwildcards slice the other way: methods that return values of the type parameter are removed)Your example is more complicated because it has nested type parameters, but it boils down to the same thing:
List<HashSet<Integer>>is a sub-type ofList<? extends Set<Integer>>List<...>) yields a pair of types that no longer have the sub/super-type relationship. That is,List<List<HashSet<Integer>>>is not a sub-type ofList<List<? extends Set<Integer>>>List<...>you wrap withList<? extends ...>you’ll end up with the original relationship being preserved. (This is just a rule of thumb, but it probably covers 80% of the cases where you’d want to use wildcards.)Note that trashgod and BalusC are both correct in that you probably don’t want to be returning such a weird type.
List<List<Set<Integer>>>would be a more normal return type to use. That should work fine as long as you’re consistent about always using the collection interfaces rather than the concrete collection classes as type parameters. eg: you can’t assign aList<ImmutableSet<Integer>>to aList<Set<Integer>>, but you can putImmutableSet<Integer>instances into aList<Set<Integer>>, so never sayList<ImmutableSet<Integer>>, sayList<Set<Integer>>.