List<? extends Base> VS List<Base>

2020-07-03 07:20发布

问题:

List<? extends Base> list

List<Base> list

Is there any difference between the two declarations?

Thanks,

回答1:

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>.



回答2:

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:

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 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.



标签: java generics