Самый простой пример, который я могу вспомнить:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
взято из того же Collections
. Таким образом, Dog
может реализовать Comparable<Animal>
, и если Animal
уже реализует это, Dog
не должен ничего делать.
РЕДАКТИРОВАТЬ для реального примера:
После некоторых электронных пинг-понгов мне разрешено представить реальный пример с моего рабочего места (ууу!).
У нас есть интерфейс под названием Sink
(не имеет значения, что он делает), идея в том, что накапливает вещей. Объявление довольно тривиально (упрощенно):
interface Sink<T> {
void accumulate(T t);
}
Очевидно, что есть вспомогательный метод, который принимает List
и сливает его элементы в Sink
(это немного сложнее, но для простоты):
public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
collection.forEach(sink::accumulate);
}
Это просто верно? Ну ...
У меня может быть List<String>
, но я хочу использовать его до Sink<Object>
- это довольно распространенная вещь для нас; но это не удастся:
Sink<Object> sink = null;
List<String> strings = List.of("abc");
drainToSink(strings, sink);
Чтобы это работало, нам нужно изменить объявление на:
public static <T> void drainToSink(List<T> collection, Sink<? super T> sink) {
....
}