Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 478
BanzaiTokyo Avatar asked Sep 05 '18 13:09

BanzaiTokyo


People also ask

What is <? Super T in Java?

super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .

What is generics explain with an example?

Generics add that type of safety feature. We will discuss that type of safety feature in later examples. Generics in Java are similar to templates in C++. For example, classes like HashSet, ArrayList, HashMap, etc., use generics very well.

What is the difference between List <? Extends T and List <? Super T >?

super is a lower bound, and extends is an upper bound.


2 Answers

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) {     .... } 
like image 71
Eugene Avatar answered Sep 30 '22 23:09

Eugene


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.

like image 45
Benoit Avatar answered Sep 30 '22 23:09

Benoit