That’s part of the concept of countervariance applied to the concept of Java generics.
Covariance in generics
Just to put it in context, covariance occurs when we use extends
and allow a more specific type (subclass) to be used in place of a more generic type.
Let’s take the example of a covariant method:
java.util.ArrayList#addAll(java.util.Collection<? extends E>)
Now suppose the following class hierarchy:
class Animal { }
class Gato extends Animal { }
class Cachorro extends Animal { }
If we have a list of Animal
, we can add lists of any subtype:
List<Gato> gatos = new ArrayList<>();
List<Cachorro> cachorros = new ArrayList<>();
List<Animal> animais = new ArrayList<>();
animais.addAll(gatos);
animais.addAll(cachorros);
Covariance is far easier to understand and more used.
Contravariance in generics
Occurs when we use super
and allow a more generic type (superclass) to be used in place of a more specific type. It is practically the opposite of covariance.
Let’s go to the example of countervariance cited in the question:
java.util.ArrayList#forEach(Consumer<? super E> action)
Now suppose the following class hierarchy:
class Animal {
void darBanho() { }
}
class Gato extends Animal { }
class Cachorro extends Animal { }
The idea here is to be able to make a list of Cachorro
or a list of Gato
may both receive a Consumer<Animal>
.
Therefore, the objective of countervariance applied to generics is to enable the reuse of generic code.
Example:
List<Gato> gatos = new ArrayList<>();
List<Cachorro> cachorros = new ArrayList<>();
gatos.forEach(Animal::darBanho);
cachorros.forEach(Animal::darBanho);
Another example:
List<Animal> animais = new ArrayList<>();
List<Gato> gatos = new ArrayList<>();
List<Cachorro> cachorros = new ArrayList<>();
Collections.copy(animais, gatos);
Collections.copy(animais, cachorros);
In the above example, the method copy
has the following signature:
void copy(List<? super T> dest, List<? extends T> src)
In other words: the destination list (dest
) may be of any generic type which is a superclass of the generic type of origin (src
). In this case, Animal
is superclass of Gato
and Cachorro
.
Therefore the use of super
in the method reinforces that the target list can always receive elements from the source list since you can always assign a specific type to a more generic type.
Countervariance is also a little counterintuitive, but it’s easier to understand if you think that it’s often interesting to treat an object or collection of objects as your most generic type for some kind of generic processing.
Could make a java7 code?
– David Schrammel
@Davidschrammel Done. Look at the second example of countervariance.
– utluiz