What is a real life example of generic <? super T>?
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 animalsCollections.copy(mammals, cats); // all cats are mammalsCollections.copy(animals, cats); // all cats are animalsCollections.copy(cats, cats); // all cats are cats
But these calls are not valid:
Collections.copy(mammals, animals); // not all animals are mammalsCollections.copy(cats, mammals); // not all mammals are catsCollections.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.
For example, look into the Collections.addAll
method implmenetation:
public static <T> boolean addAll(Collection<? super T> c, T... elements) { boolean result = false; for (T element : elements) result |= c.add(element); return result;}
Here, the elements can be inserted into any collection whose element type is a supertype of the type T
of the element.
Without a lower bounded wildcard:
public static <T> boolean addAll(Collection<T> c, T... elements) { ... }
the following would have been invalid:
List<Number> nums = new ArrayList<>();Collections.<Integer>addAll(nums , 1, 2, 3);
because the term Collection<T>
is more restrictive than Collection<? super T>
.
Another example:
Predicate<T>
interface in Java, that uses a <? super T>
wildcard in the following methods:
default Predicate<T> and(Predicate<? super T> other);default Predicate<T> or(Predicate<? super T> other);
<? super T>
allows to chain a wider range of different predicates, for example:
Predicate<String> p1 = s -> s.equals("P");Predicate<Object> p2 = o -> o.equals("P");p1.and(p2).test("P"); // which wouldn't be possible with a Predicate<T> as a parameter