Here is another approach, but others gave a quite detailed response.
The first example:
List<? extends Object> ls0 = new LinkedList<Number>();
addandDisp(ls0, new Object());
Here ls0
may be of any type that is a subclass of Object
, like a Number
as your example shows.
Now what if this could work? It would mean that if you can put an Object
into any of the collections.
Imagine I want to iterate your previous list of Number
objects:
for (Number n : numbers) {
...
}
If I could put an Object
here, then Plaff! I would get a class cast exception immediately.
The second example
List<? super String> ls1 = ...;
addandDisp(ls1,new String());
Let's play a bit with the object hierarchy: String
is a subclass of CharSequence
which is a subclass of Object
.
You get ls1
here which is an unknown supertype of String (e.g., a CharSequence
). Is it all right to put a String
into a list of character sequences? Yup, it's okay, since they share the same interface for sure! You can handle them through it in the same way.
The third example
List<? super String> ls1 = ...;
addandDisp(ls1,new Object());
Let's suppose the previous situation: you assign ls1
a list of CharSequence
s. Can you add an object to a List<CharSequence>
? Nope, for the same reason as the first example fails.
Hope that helps clarifying your issues a bit :-)