-1

Look at this two examples:

void printCollection(Collection<Object> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

vs

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

What is the difference between these two? I read that the second example is more powerful. But why is that? Which argument you can't pass to method 1, which you can pass to method 2?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
Chris311
  • 3,794
  • 9
  • 46
  • 80

1 Answers1

3

Generics aren't covariant. In other words, a Collection<String> is not a Collection<Object>, even though a String is an Object. With the first signature, I wouldn't be able print a List<String> for example.

Generic wildcards assist in the expression of covariance (as in your example) and contravariance. Collection<?> is short for Collection<? extends Object> and means "a collection of some specific, unknown type that is or extends Object". As a consequence, we wouldn't be able to add anything but null to such a collection since we couldn't guarantee the added object's type would be valid.

Here's an example that uses a wildcard to express contravariance:

void populateCollection(Collection<? super Integer> c) {
    for (int i = 0; i < 10; i++) {
        c.add(i);
    }
}

I could pass a Collection<Object>, Collection<Number>, or Collection<Integer> into this method, since it's treated as a consumer of Integers. In your example, the collection is a producer of Objects. See this post for further reading on the distinction between "producers" and "consumers" with respect to wildcarded generic types: What is PECS (Producer Extends Consumer Super)?

Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181