2

Take a look at the next code:

ArrayList<? extends Object> list = new ArrayList<Object>();
list.add(new Object());

It does not compile. The question is why?

Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216

3 Answers3

6
ArrayList<? extends Object>

is the same as just

ArrayList<?>

and you can assign any ArrayList to a variable of this type. For example,

ArrayList<? extends Object> list = new ArrayList<String>();

is legal. Clearly, the language semantics will not let you add an Object to such a list. In fact, they won't let you add anything at all to it, except null, or something which you directly retrieved from the list.

As noted by Lukas in the comment, it is far from trivial to even add the list's own item back to it: you need a helper method to capture the wildcard into a named type.

public static void main(String[] args) {
  ArrayList<? extends Object> list = new ArrayList<String>();
  addOwn(list);
}
static <T> void addOwn(List<T> l) { l.add(l.get(0)); }
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • *or something which you directly retrieved from the list.*: That would surprise me. Can you show an example? :-) – Lukas Eder Nov 23 '13 at 14:38
  • That's cheating ;-) You can of course add `T` to a `List`. But that `List` is no longer a `List extends Object>` – Lukas Eder Nov 23 '13 at 14:47
  • @LukasEder A lot of things with Java Generics can be construed as cheating :) This is a common idiom to solve the use case in question and the point is that you did start with a weakly typed object and managed to upgrade the type. – Marko Topolnik Nov 23 '13 at 14:48
  • I know. I had actually been looking for a formal explanation in the JLS for this, recently: http://stackoverflow.com/q/11500385/521799 – Lukas Eder Nov 23 '13 at 14:49
  • @LukasEder I was fully aware that you knew :) – Marko Topolnik Nov 23 '13 at 14:51
  • 1
    Come on. How did you know? ;-) – Lukas Eder Nov 23 '13 at 14:52
  • 1
    Note, here's another "common idiom" to work around that silly limitation of the Java language: http://stackoverflow.com/a/11982573/521799 ;-) – Lukas Eder Nov 23 '13 at 14:53
  • 1
    I'd just note that you never know whether they just lacked the time or hit a brick wall with some edge cases the formal specification of this would have. – Marko Topolnik Nov 23 '13 at 15:00
  • 1
    That's why I had asked, back then. Unfortunately, it is hard to get authoritative answers on these matters. Few people remember relevant mailing list threads from 10 years ago. In this case, getting this "feature" correct would just not pull its weight, I guess. – Lukas Eder Nov 23 '13 at 15:07
2

I think the reason is because Generic types are not polymorphic. When you use wildcards ? with extends you cant add anything in the collection except null.

Here is an example to what will happen if that is allowed:

Class Car{

}
class A extends Car {

}
class B extends Car{

}

Now you have List<? extends Car>

public void someMethod(List<? extends Car> list){
list.add(new A()); //this is not valid
}

Also you may invoke the method like this:

List<B> someList = new Array:list<B>(); 
somemethod(someList);
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
2

The problem is that Foo extends Object does not mean Collection<Foo> can be treated as a subtype of Collection<Object>. This is simply because the former class does not permit you to do everything the latter does; for instance, you cannot add an Object to a Collection<Foo>. Using generics instead of some concrete class Foo doesn't change this.

Jose Torres
  • 347
  • 1
  • 3