Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are wildcard generics really needed?

Tags:

java

generics

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?

like image 563
lovespring Avatar asked Apr 05 '14 21:04

lovespring


3 Answers

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
}
like image 112
newacct Avatar answered Nov 02 '22 01:11

newacct


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.

like image 24
Michał Kosmulski Avatar answered Nov 02 '22 00:11

Michał Kosmulski


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.

like image 31
kgautron Avatar answered Nov 02 '22 01:11

kgautron