Найпростіший приклад, який я можу придумати, це:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
взято з того самого Collections
. Таким чином a Dog
може реалізувати, Comparable<Animal>
і якщо Animal
вже реалізує це, Dog
не потрібно нічого робити.
EDIT для реального прикладу:
Після кількох електронних пінг-понгів, мені дозволено подати реальний приклад зі свого робочого місця (так!).
У нас є інтерфейс, який називається Sink
(неважливо, що він робить), ідея полягає в тому, що це накопичує речі. Заява досить тривіальна (спрощена):
interface Sink<T> {
void accumulate(T t);
}
Очевидно, що є допоміжний метод, який приймає a List
і зливає його елементи в a Sink
(це дещо складніше, але для спрощення):
public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
collection.forEach(sink::accumulate);
}
Це просто так? Ну...
Я можу взяти a List<String>
, але я хочу злити його до a 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) {
....
}