Найпростіший приклад, який я можу придумати, це:
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) {
....
}