Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use wildcards in Java Generics?

this is from HeadFirst Java: ( page 575 )

This:

public <T extends Animal> void takeThing(ArrayList<T> list) 

Does the same thing as this:

public void takeThing(ArrayList<? extends Animal> list) 

So here is my question: if they are exactly same, why don't we write

public <? extends Animal> void takeThing(ArrayList<?> list) 

or

public void takeThing(ArrayList<T extends Animal> list) 

Also, when would it be useful to use a ? instead of a T in a method declaration ( as above ) with Generics, or for a Class declaration? What are the benefits?

like image 883
Koray Tugay Avatar asked May 23 '13 06:05

Koray Tugay


People also ask

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.

What is the use of wildcard in generics?

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

Where are wildcards used in Java?

In the Java programming language, the wildcard ? is a special kind of type argument that controls the type safety of the use of generic (parameterized) types. It can be used in variable declarations and instantiations as well as in method definitions, but not in the definition of a generic type.

What is the difference between bounded and unbounded wildcards in Java generics?

both bounded and unbounded wildcards provide a lot of flexibility on API design especially because Generics is not covariant and List<String> can not be used in place of List<Object>. Bounded wildcards allow you to write methods that can operate on Collection of Type as well as Collection of Type subclasses.


2 Answers

The big difference between

public <T extends Animal> void takeThing(ArrayList<T> list) 

and

public void takeThing(ArrayList<? extends Animal> list) 

is that in the former method you can refer to "T" within the method as the concrete class that was given. In the second method you cannot do this.

Here a more complex example to illustrate this:

// here i can return the concrete type that was passed in public <T extends Animal> Map<T, String> getNamesMap(ArrayList<T> list) {     Map<T, String> names = new HashMap<T, String>();     for (T animal : list) {         names.put(animal, animal.getName()); // I assume there is a getName() method     }     return names; }  // here i have to use general Animal public Map<Animal, String> getNamesMap(ArrayList<? extends Animal> list) {     Map<Animal, String> names = new HashMap<Animal, String>();     for (Animal animal : list) {         names.put(animal, animal.getName()); // I assume there is a getName() method     }     return names; } 

With the first method if you pass in an List of Cats you get a Map with Cat as key. The second method would always return a Map with general Animal key.

By the way this is not valid java syntax:

public <? extends Animal> void takeThing(ArrayList<?> list) 

Using this form of generic method declaration you have to use a valid java identifier and not "?".

Edit:

The form "? extends Type" only applies to variable or parameter type declaration. Within a generic method declration it has to be "Identifier extends Type" as you are able to refer to the "Identifier" from within your method.

like image 70
Werzi2001 Avatar answered Oct 16 '22 12:10

Werzi2001


Wild cards are about co/contra variance of generics. I will try to make clear what this means by providing some examples.

Basically it is related to the fact that for types S and T, where S is a subtype of T, a generic type G<S> is not a valid subtype of G<T>

List<Number> someNumbers = new ArrayList<Long>(); // compile error 

You can remedy this with wild cards

List<? extends Number> someNumbers = new ArrayList<Long>(); // this works 

Please note, that you can not put anything into such a list

someNumbers.add(2L); //compile error 

even (and more surprising for many developers):

List<? extends Long> someLongs = new ArrayList<Long>(); someLongs.add(2L); // compile error !!! 

I think SO is not the right place to discuss that in detail. I will try to find some of the articles and papers that explain this in more detail.

like image 24
bennidi Avatar answered Oct 16 '22 13:10

bennidi