Does anyone know why the following code does not compile? Neither add() nor addAll() works as expected. Removing the "? extends" part makes everything work, but then I would not be able to add subclasses of Foo.
List<? extends Foo> list1 = new ArrayList<Foo>(); List<? extends Foo> list2 = new ArrayList<Foo>(); /* Won't compile */ list2.add( new Foo() ); //error 1 list1.addAll(list2); //error 2
error 1:
IntelliJ says:
add(capture<? extends Foo>) in List cannot be applied to add(Foo)
The compiler says:
cannot find symbol symbol : method addAll(java.util.List<capture#692 of ? extends Foo>) location: interface java.util.List<capture#128 of ? extends Foo>
error 2:
IntelliJ gives me
addAll(java.util.Collection<? extends capture<? extends Foo>>) in List cannot be applied to addAll(java.util.List<capture<? extends Foo>>)
Whereas the compiler just says
cannot find symbol symbol : method addAll(java.util.List<capture#692 of ? extends Foo>) location: interface java.util.List<capture#128 of ? extends Foo> list1.addAll(list2);
In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).
Guidelines for Wildcards. Upper bound wildcard − If a variable is of in category, use extends keyword with wildcard. Lower bound wildcard − If a variable is of out category, use super keyword with wildcard. Unbounded wildcard − If a variable can be accessed using Object class method then use an unbound wildcard.
Wildcards in Java are basically the question marks which we use in generic programming, it basically represents the unknown type. We use Java Wildcard widely in situations such as in a type of parameter, local variable, or field and also as a return type.
(I assume here that Bar
and Baz
are both subtypes of Foo
.)
List<? extends Foo>
means a list of elements of some type, which is a subtype of Foo, but we don't know which type. Examples of such lists would be a ArrayList<Foo>
, a LinkedList<Bar>
and a ArrayList<Baz>
.
As we don't know which subtype is the type parameter, we can't put Foo
objects into it, neither Bar
or Baz
objects. But we still know that the type parameter is a subtype of Foo
, so every element already in the list (and which we can get from the list) must be a Foo
object, so we can use Foo f = list.get(0);
and similar things.
Such a list can only be used for taking elements out of the list, not to adding elements at all (apart from null
, but I don't know if the compiler actually allows this).
A List<Foo>
on the other hand allows adding any object which is a Foo
object - and as Bar
and Baz
are subtypes of Foo
, all Bar
and Baz
objects are Foo
objects, so they can be added, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With