class Employee<T extends Number> { // valid
}
class Employee<? extends Number> { // invalid
}
private static void test(List<? super Number> list1) { // valid
}
private static <T>void test(List<T super Number> list1) { // invalid
}
what exactly is difference between ?
and T
and when to use what?
Why with class definition, ?
doesn't work but it works with List
and why T
works with class definition but not with List
?
You can not use a generic type token T
before introducing it.
In your method example you try to declare the T
at the wrong spot, that is invalid syntax. You have to introduce it beforehand.
For the class example however, you have put it in the right spot.
Here is where you can introduce your generic type token on a class wide level:
public class Foo< HERE > { ... }
and thats how you do it for a method only:
public < HERE > void foo(...) { ... }
In both cases you can bound your T
, like T extends Number
and then use it accordingly:
public class Foo<T extends Number> { ... }
// or
public <T extends Number> void foo(...) { ... }
After you have introduced your T
, you will use it just like that. So List<T>
, as an example.
public <T extends Number> void foo(List<T> list) { ... }
Note that T super Number
is invalid on as it makes little sense and does not provide more information than just T
or Number
or simply Object
, depending on what you are trying to achieve. You can read more about that at Java generic methods: super can't be used?
Wildcards are a different thing. They are not a generic type token that you have to introduce first, such as T
. Instead, they clarify the type range you want to accept.
For example a method like
public static void foo(List<? super Dog> list) { ... }
can be called with a List<Dog>
, a List<Animal>
or even a List<Object>
. We call such a list a consumer of Dog
s. To be precise, these are all lists that would accept a dog, so list.add(new Dog())
will work.
On the other side, we have
public static void foo(List<? extends Dog> list) { ... }
which can be called with a List<Dog>
or also a List<Chihuahua>
. We call such a list a producer (or provider) of Dog
s. To be precise, these are all lists that can provide dogs. So Dog dog = list.get(0)
will work.
You can read more about the details of what wildcards are and how they work at What is PECS (Producer Extends Consumer Super)?
In general, you would use a generic type token T
when you actually still need to maintain the type safety throughout your code. I.e. when you need to be able to give the type a name. Otherwise you use wildcards ?
.
For example, suppose you want to create a method that takes in a list and an element to add to it:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
You need to introduce the T
to ensure that the type of the list matches the given element. Otherwise someone could do addToList(dogs, cat)
, which you do not want.
If you do not have the need to actually name the type, you can also just use a wildcard. For example a method that takes a list and prints all its contents:
public static void printAll(List<?> list) {
for (Object object : list) {
System.out.println(object);
}
}