Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lists with wildcards cause Generic voodoo error

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); 
like image 296
oligofren Avatar asked Mar 23 '11 15:03

oligofren


People also ask

What are generic wildcards?

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

How do you use generic wildcards?

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.

Why do we use wildcards in Java generics?

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.


1 Answers

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

like image 127
Paŭlo Ebermann Avatar answered Oct 09 '22 04:10

Paŭlo Ebermann