Ví dụ dễ nhất mà tôi có thể nghĩ đến là:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
lấy từ cùng một Collections
. Cách này a Dog
có thể thực hiện Comparable<Animal>
và nếu Animal
đã thực hiện Dog
thì không phải làm gì cả.
CHỈNH SỬA cho một ví dụ thực tế:
Sau một số trận bóng bàn qua email, tôi được phép trình bày một ví dụ thực tế từ nơi làm việc của tôi (vâng!).
Chúng ta có một giao diện được gọi là Sink
(nó không quan trọng nó làm gì), ý tưởng là tích lũy mọi thứ. Khai báo khá đơn giản (đơn giản hóa):
interface Sink<T> {
void accumulate(T t);
}
Rõ ràng là có một phương thức trợ giúp lấy a List
và rút các phần tử của nó thành a Sink
(phức tạp hơn một chút, nhưng để làm cho nó đơn giản):
public static <T> void drainToSink(List<T> collection, Sink<T> sink) {
collection.forEach(sink::accumulate);
}
Điều này thật đơn giản phải không? Tốt...
Tôi có thể có a List<String>
, nhưng tôi muốn rút cạn nó thành a Sink<Object>
- đây là một việc khá phổ biến đối với chúng ta; nhưng điều này sẽ thất bại:
Sink<Object> sink = null;
List<String> strings = List.of("abc");
drainToSink(strings, sink);
Để điều này hoạt động, chúng ta cần thay đổi khai báo thành:
public static <T> void drainToSink(List<T> collection, Sink<? super T> sink) {
....
}