The easiest example I can think of is:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
taken from the same Collections
. This way a Dog
can implement Comparable<Animal>
and if Animal
already implements that, Dog
does not have to do anything.
EDIT for a real example:
After some email ping-pongs, I am allowed to present a real example from my work-place (yay!).
We have an interface called Sink
(it does not matter what it does), the idea is that is accumulates things. The declaration is pretty trivial (simplified):
interface Sink<T> {
void accumulate(T t);
}
Obviously there is a helper method that takes a List
and drains it's elements to a Sink
(it's a bit more complicated, but to make it simple):
public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
collection.forEach(sink::accumulate);
}
This is simple right? Well...
I can have a List<String>
, but I want to drain it to a Sink<Object>
- this is a fairly common thing to do for us; but this will fail:
Sink<Object> sink = null;
List<String> strings = List.of("abc");
drainToSink(strings, sink);
For this to work we need to change the declaration to:
public static <T> void drainToSink(List<T> collection, Sink<? super T> sink) {
....
}