Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Wildcards again

Tags:

java

generics

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 ArrayLists:

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 Objects I use parametrized types (much more elegant I think).

So, the main question remains: Why do we need wildcards?

like image 916
Aldsjers Dostrnik Avatar asked Sep 10 '12 09:09

Aldsjers Dostrnik


2 Answers

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.

like image 31
Jon Lin Avatar answered Oct 25 '22 20:10

Jon Lin


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)

like image 51
Roberto Mereghetti Avatar answered Oct 25 '22 22:10

Roberto Mereghetti