List<Base> list can contain elements of type Base or any of its subtypes. Some example with the JDK classes:
List<Object> objects = new ArrayList<Object>();
objects.add(new Object()); // adding an Object instance
objects.add("I am a String"); // a String instance is also an Object
objects.add(Integer.valueOf(5)); // an Integer instance is also an Object
But when you retrieve the elements, you can assign them only to variables of the Object class, because Object is the type parameter of the declared list.
Object first = objects.get(1);
Object second = objects.get(2);
Object third = objects.get(3);
Their real runtime classes are still Object, String and Integer, so you can cast them to those types and work with them as such, but such casts may fail at runtime with a ClassCastException if not done right and it's generally not a good idea to work with lists in such fashion.
List<? extends Base> list is a declaration that is not actually designated for declaring variables, because as already mentioned in Daniel Pryden's comment - you cannot add() any object in it, only nulls.
List<? extends String> list = new ArrayList<? extends String>();
list.add("a String")); // compile error!
But you can use such a bounded wildcard expression for generic method parameters. An example from the List itself is the addAll() method whose signature is this:
Without the <? extend E> wildcard it wouldn't be possible to add those Strings into the List of Objects, because generic types (unlike arrays) are not covariant. That means that a List<String>is not a subtype of List<Object>. But any String is an Object, right? So therefore it is necessary to declare the method parameter with the bounded wildcard - a List<String>is a subtype of List<? extends Object>.
Again, I have to point out - the bounded wildcard are primarily designated for generic method parameters, not for method return types or variable declarations.
List<Base> can contain a mixture of different things that all derive from Base. List<? extend Base> contains homogeneous items (in the sense that they must all derive from some specific, unknown type that in turn derives from Base).
Put another way, List<? extends Base> is the base class for List<T extends Base>. So you can pass a List<T extends Base> to any method that takes a List<? extends Base>. The same is not true for methods that take a List<Base>.
List<Base> list
can contain elements of typeBase
or any of its subtypes. Some example with the JDK classes:But when you retrieve the elements, you can assign them only to variables of the
Object
class, becauseObject
is the type parameter of the declared list.Their real runtime classes are still
Object
,String
andInteger
, so you can cast them to those types and work with them as such, but such casts may fail at runtime with aClassCastException
if not done right and it's generally not a good idea to work with lists in such fashion.List<? extends Base> list
is a declaration that is not actually designated for declaring variables, because as already mentioned in Daniel Pryden's comment - you cannotadd()
any object in it, onlynull
s.But you can use such a bounded wildcard expression for generic method parameters. An example from the
List
itself is theaddAll()
method whose signature is this:This enables you to do something like this:
Without the
<? extend E>
wildcard it wouldn't be possible to add thoseString
s into theList
ofObject
s, because generic types (unlike arrays) are not covariant. That means that aList<String>
is not a subtype ofList<Object>
. But anyString
is anObject
, right? So therefore it is necessary to declare the method parameter with the bounded wildcard - aList<String>
is a subtype ofList<? extends Object>
.Again, I have to point out - the bounded wildcard are primarily designated for generic method parameters, not for method return types or variable declarations.
Yes.
List<Base>
can contain a mixture of different things that all derive fromBase
.List<? extend Base>
contains homogeneous items (in the sense that they must all derive from some specific, unknown type that in turn derives fromBase
).Put another way,
List<? extends Base>
is the base class forList<T extends Base>
. So you can pass aList<T extends Base>
to any method that takes aList<? extends Base>
. The same is not true for methods that take aList<Base>
.