List<? extends Base> list
List<Base> list
Is there any difference between the two declarations?
Thanks,
List<? extends Base> list
List<Base> list
Is there any difference between the two declarations?
Thanks,
Yes.
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 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 null
s.
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:
boolean addAll(Collection<? extends E> c);
This enables you to do something like this:
List<String> strings = Arrays.asList("a", "b");
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);
Without the <? extend E>
wildcard it wouldn't be possible to add those String
s into the List
of Object
s, 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.