Java type system ensures type restrictions, e.g.:
class Object {
// We specify a method to return String, not Object
public String toString();
}
Sometimes we want to apply the same restrictions to type parameters as well. When implementing a method that searches for a maximum of a collection we want to be sure that collection elements could be compared with each other, so the code below would not provide compile-time safety:
class Collections {
public static <T> T max(Collection<T> coll) { ... }
}
class Collections {
public static <T> T max(Collection<T> coll) {
...
T currentMax = coll.iterator().next();
...
T currentElement = ...
// Now we want to compare current element and current max
((Comparable<T>) currentMax).compareTo(currentElement); // this may fail at runtime!
}
}
To restrict the type of elements to the ones implementing Comparable<T> type bounds could be used:
public static <T extends Comparable<T>> T max(Collection<T> coll) { ... }
This code may be future improved by applying the Get and Put principle to make method signature as general as possible to maximize utility:
public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll) { ... }
Type bound may have the form of single type variable:
<T extends Type>
or class/interface type possibly followed by interface types:
<T extends Type & InterfaceType1 & InterfaceType2 & ... >
Under the hood every type variable declared as a type parameter has a bound. If no bound is declared for a type variable, Object is assumed. So:
class SomeClass<T> { ... }
class SomeClass<T extends Object> {...}