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?
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
}
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.
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.
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