They are the same in that they accept the same parameter types.
However, identifying the type with T
(or whatever) lets you refer to the type elsewhere.
Edit: Examples:
Your unbounded examples do not make full use of the capabilities of parameterized types. You have:
public static <T> void printList(List<T> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}
And that's sufficient for that example of printing string representations, but consider this (very contrived, and no error handling):
public static <T> T getSecondItem (List<T> list) {
T item = list.get(1);
return item;
}
The return type is T, which allows you to safely do things like this, with compile time type-checking:
class MyClass {
public void myMethod () { }
}
void somewhere () {
List<MyClass> items = ...;
getSecondItem(items).myMethod();
}
A named type also lets you share the same type constraint in multiple places, e.g.:
public <T> int compareLists (List<T> a, List<T> b) {
...
}
If you did not name the type, you could not specify the constraint that a
and b
are the same list type (you could use List<? extends T>
for more flexibility).
You also asked "Why do I need ?
?". The real answer is: You don't. It's mostly for aesthetics, I suppose. Java strives to be a precise and clutter-free language. There are many situations where you simply don't care what type you are referring to. In those cases, you may use ?
without cluttering code with unused type parameter declarations.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…