In Java, the type arguments must match exactly.
Consider the following code snippet:
ArrayList<Object> list = new ArrayList<String>();
list.add(new SomeClass());
We have now succeeded in adding a non-string to ArrayList<String>
. There is nothing wrong with the second statement: we're adding some object to an ArrayList<Object>
. So there must be something wrong with the first statement! That's why Java does not let you do that.
If you change the snippet to:
ArrayList<? extends Object> list = new ArrayList<String>();
list.add(new SomeClass());
you will notice that the error is now in the second line. You cannot add an object to the list.
The difference between the two is the following:
ArrayList<Object>
means "an ArrayList containing Object
s". Such a list can of course also contain instances of subclasses of Object
. Since every object is an instance of Object
, this list can contain any object (in this case).
ArrayList<? extends Object>
means "an ArrayList containing instances of some unknown subclass of Object
". Such an ArrayList cannot contain every object. Only instances of this unknown subclass can be added to it. Since the specific subclass is not known, it is not possible to add elements to it here. (But elsewhere, the same list may be known as an ArrayList<String>
, and there it is of course possible to add elements to it.)