13

for example:

    public String add(Set<?> t){
    ...;
    }



    public <T> String add(Set<T> t){
    ...;
    }

The first uses wildcard generics; the second is the normal form of a generic method. What's the difference?

In what situation do we need wildcard generics, not the normal form of generics?

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
lovespring
  • 19,051
  • 42
  • 103
  • 153

4 Answers4

12

Here is a situation where wildcards are required. This method takes a List<List<?>>, which is a list of lists. The method can add lists of different component types into it:

public void foo(List<List<?>> t) {
    t.add(new ArrayList<String>());
    t.add(new ArrayList<Integer>());
}

You cannot do this using generic type parameters without wildcards. For example, the following does not work:

public <T> void foo(List<List<T>> t) {
    t.add(new ArrayList<String>()); // does not compile
    t.add(new ArrayList<Integer>()); // does not compile
}
newacct
  • 119,665
  • 29
  • 163
  • 224
  • +1 IMO nested wildcards should have had a different symbol like `*` since their meaning is different. But return types with top-level wildcards like from `Class.forName` are a great example of them being necessary. – Paul Bellora Apr 06 '14 at 18:39
11

Since support for generics was added, using a parameterized type without providing a type parameter usually causes a compiler warning. On the other hand, there are situations where you don't care at all what the type parameter is (i.e. you don't use the type anywhere) or, even worse, you might not know what T is at all, and using <?> lets you express just that without causing a compiler warning.

Possible use case for the "don't care" case (very simple for brevity, but you get the idea):

public void clearList(List<?> list) {
    list.clear();
}

An example for the "don't know" case: an actual method signature from Class class:

static Class<?> forName(String className);

Here the method returns an object of some Class type. Class is generic but of course you don't know the type because it depends on the className parameter which is resolved at runtime. So you can't put T here since T is not known at compile time (even for a particular call site), and using just Class without type parameter would be a bad practice and cause a compiler warning.

Michał Kosmulski
  • 9,855
  • 1
  • 32
  • 51
  • But in that last case, you could write `static Class forName(String className)` and it would be OK. There is no case when you actually **need** `>`. – Dawood ibn Kareem Apr 06 '14 at 01:09
  • 6
    @DavidWallace: Those two are completely different. `Class> forName(String className);` returns a `Class` of unknown parameter. ` Class forName(String className);` returns a `Class` of whatever parameter the caller wants (without knowing what that parameter is). That is obviously impossible to implement safely, unless it always returns `null`. – newacct Apr 06 '14 at 02:21
1

The wildcard form is when you don't mind what types of objects you are handling.

The generics form allows you to add contraints on the type of objects handled.

An example use case could be the following : a generic repository with add/update/remove methods, you define common behavior using the generic type :

public class Repository<T>{
 public void add(T t){...}
 public void update(T t){...}
 public void remove(T t){...}
}

Then to make a repository for Apple and Banana you just extend this class and replace T with the real type :

public class AppleRepo extends Repository<Apple> {}
public class BananaRepo extends Repository<Banana> {}

If the generic Repository was declared as Repository<?>, it would not be good because it is not restricted to Banana, and you would not be able to use Banana specific methods inside it without casting objects;

Also the generics allow you to express further constraints, for example

Repository<T extends Fruit>

allows you to restrict the generic repository class to fruits. And you will be able to make calls to Fruit methods in its code.

kgautron
  • 7,915
  • 9
  • 39
  • 60
  • 4
    Sure, but this doesn't answer the question. The question is what situation would _require_ the wildcard; in other words, is there something that we can do with wildcards, for which the other syntax won't work. – Dawood ibn Kareem Apr 05 '14 at 22:13
0

There's not difference in calling the methods.

In the second method (add(Set<T>)) you can create variables of type T:

public <T> String add(Set<T> t){
    T item = t.iterator().next();
    //....
}

That gives you some additional type checking. In the first method you're left with using Object.

rzymek
  • 9,064
  • 2
  • 45
  • 59
  • 3
    Sure, but this doesn't answer the question. The question is what situation would _require_ the wildcard; in other words, is there something that we can do with wildcards, for which the other syntax won't work. – Dawood ibn Kareem Apr 05 '14 at 22:12