What is a real life example of generic <? super T>?
I understand that <? super T>
represents any super class of T
(parent class of T
of any level). But I really struggle to imagine any real life example for this generic bound wildcard.
I understand what <? super T>
means and I have seen this method:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
I am looking for an example of real life use case where this construction can be used and not for an explanation of what it is.
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) {
....
}
Suppose you have this class hierarchy: Cat inherits from Mammal, which in turn inherits from Animal.
List<Animal> animals = new ArrayList<>();
List<Mammal> mammals = new ArrayList<>();
List<Cat> cats = ...
These calls are valid:
Collections.copy(animals, mammals); // all mammals are animals
Collections.copy(mammals, cats); // all cats are mammals
Collections.copy(animals, cats); // all cats are animals
Collections.copy(cats, cats); // all cats are cats
But these calls are not valid:
Collections.copy(mammals, animals); // not all animals are mammals
Collections.copy(cats, mammals); // not all mammals are cats
Collections.copy(cats, animals); // mot all animals are cats
So the method signature simply insures that you copy from a more specific (lower in the inheritance hierarchy) class to a more generic class (upper in the inheritance hierarchy), and not the other way round.