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.