In my last question (thank you all that answer me), I have learnt the difference between List<Object>
and List<?>
.
However I still can't see the usefulness of wildcards.
I have two ArrayList
s:
ArrayList<Integer> li = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList<String> ls = new ArrayList<String>(Arrays.asList("one","two","three"));
Now, look at the two blocks of code below:
static void printList(ArrayList<?> list)
{
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
and
static <T> void printList(ArrayList<T> list)
{
for (T elem: list)
System.out.print(elem + " ");
System.out.println();
}
When I call:
printList(li);
printList(ls);
Both methods return the output:
1 2 3
one two three
However the second solution, in the for loop, instead of Object
s I use parametrized types (much more elegant I think).
So, the main question remains: Why do we need wildcards?
In the Java Generics Tutorial it says:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
On the other hand, given a List, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.
So having a wildcard type ensures that we can't add()
to the List, with the exception of null
. If you are just calling get()
on the List, you know that it is at least an Object.
If the question is "usefulness of wildcards":
Wildcards are useful when only partial knowledge about the type parameter is required. "Partial knowledge" is implemented by the upper and lower bounds (? super T or ? extends T); if you use only the unbound wildcard ( ? ) you mean no knowledge at all, and you can't see where wildcards are really useful.
Wildcards can be used in composition with type parameters, to create relationships between the type of method parameters, return type and exception types. So an example of useful wildcard is
class ListManager<T> {
public void add(T item, List<? super T> list) {
[... some useful operation ...]
list.add(item);
}
}
public class Main {
public static void main(String[] args) {
List<Object> list = new ArrayList<Object>();
Integer item = 10;
ListManager<Integer> manager = new ListManager<Integer>();
manager.add(item, list);
}
}
The method "ListManager.add()" creates a relationship between type of "list" and type of "item". The operation on "list" is always type safe, but you can use method "add" with list of different parameter type: we have used the minimum constraint on parameter "list".
(see also jls7 documentation)
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