5

I was wondering why the following bit of code does not work:

Collection <? super String> col = new ArrayList<String>();
col.add(new Object());// does not compile
col.add("yo!");// compiles indeed;

If the type is <? super String> it can contain anything which is super of String (String included) not?

Jonathan
  • 20,053
  • 6
  • 63
  • 70
Rollerball
  • 12,618
  • 23
  • 92
  • 161

2 Answers2

15

Collection<? super String>, counter to your intuition, does not mean "a collection which contains objects of type String or its supertype". It means "col will be a collection holding some definite type, which itself is String or its supertype" (such as Object, Serializable, or CharSequence).

The best way to think about Collection<? super String> is that it is not a type, like you are used to in Java, but a pattern against which specific types are matched.

Now, the only thing you can safely add to any collection which matches the above pattern is a String or its subclass (if there were any). Quite the opposite of what you would have expected, isn't it? That's Generics for you.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
3

With a Collection <? super String>, we don't know what kind of objects it contains exactly, but we know that it must be a collection of either String or some superclass of String, i.e. it is safe to put a String into it but not necessarily an Object. Conversely for methods that take things out of the collection (e.g. when iterating) we can't be sure we'll get strings back.

On the other hand with Collection<? extends Foo> we know it's a collection of something that is either Foo or some subclass of Foo, so we can safely take something from the collection and know it will be assignable to Foo, but we can't put anything in because we have no way of knowing what types would be safe.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183