34

This compiles (1.6)

List<? extends Object> l = new ArrayList<Date>();

But this does not

List<List<? extends Object>> ll = new ArrayList<List<Date>>();

with the error of

Type mismatch: cannot convert from ArrayList<List<Date>> to List<List<? extends Object>>

Could someone explain why? Thanks

EDIT: edited for being consequent

bpgergo
  • 15,669
  • 5
  • 44
  • 68

5 Answers5

24

Well the explanations are correct, but I think it'd be a nice thing to add the actual working solution as well ;)

List<? extends List<? extends Object>>

Will work just fine, but obviously the use of such a collection is quite limited by the usual limitations of generic Collections (but then the same is true for the simpler List< ? extends Date >)

Voo
  • 29,040
  • 11
  • 82
  • 156
15

Because it would break type safety:

List<List<Object>> lo = new ArrayList<List<Object>>();
List<List<? extends Object>> ll = lo;
List<String> ls = new ArrayList<String>();
ll.add(ls);
lo.get(0).add(new Object());
String s = ls.get(0); // assigns a plain Object instance to a String reference
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • People may want to read up on C#'s covariant/contravariant declarations for generic interfaces and delegates which was added in 4.0. That is one way to "solve" this problem (well it changes the problem first) – Voo Jun 09 '11 at 14:20
  • 3
    @Voo see a very old paper "On Variance-Based Subtyping for Parametric Types". the two approaches were analyzed for their pros/cons. Java went one way, C# went another way, but there is nothing new. C#'s approach appears simple in simple case, but the complexity easily becomes unmanageable, as the paper stated. (I don't appreciate C# people present it as something they invented and magical without flaw) – irreputable Jun 09 '11 at 14:36
  • @irreputable Will look at the paper if I have time for some surely highly non trivial talk about co/contravariance ;) And well Generics are complicated to begin with but being able to express co/contravariance can be useful sometimes. But sure nothing for the faint-hearted. But then Java didn't have a choice to begin with - I don't see how that could be implemented backwards compatible. But then I think everybody agrees that Java's implementation is horrible as is, so really no good idea to add anything on top of it – Voo Jun 09 '11 at 15:50
  • lo.get(0).add(new Object()); would raise an error, since you try to add an object to a list of string. – clapas Oct 03 '14 at 14:51
  • @Voo Scala also does it that way. – Rag Jun 03 '15 at 21:29
3

Suppose D is subtype of B, G<T> is a generic type

B x = new D(); // OK

G<B> y = new G<D>(); // FAIL

Now, G<Date> is a subtype of G<?>, therefore

G<?> x = new G<Date>();  // OK

G<G<?>> y = new G<G<Date>>(); // FAIL
irreputable
  • 44,725
  • 9
  • 65
  • 93
2

When assigning to a variable (List<T>) with a non-wildcard generic type T, the object being assigned must have exactly T as its generic type (including all generic type parameters of T, wildcard and non-wildcard). In your case T is List<? extends Object>, which is not the same type as List<Date>.

What you can do, because List<Date> is assignable to List<? extends Object>, is use the wildcard type:

List<? extends List<? extends Object>> a = new ArrayList<List<Date>>();
ILMTitan
  • 10,751
  • 3
  • 30
  • 46
0
<? extends Object>  

means that the wildcard could be substituted only for those objects, that are subclass of Object class.

List<List<? extends Object>> ll = new ArrayList<List<Object>>();  

gives you error of type mismatch because you are trying to assign a ArrayList of List of object of java class Object to a List that contains the List of any type of objects that are subclass of java class Object.

For more ref, have a look at the Wildcard documentation

Saurabh Gokhale
  • 53,625
  • 36
  • 139
  • 164