What is a real life example of generic <? super T>? What is a real life example of generic <? super T>? java java

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