Middle
What directions can variability in generics be directed towards?
sobes.tech AI
Answer from AI
Variance in generics can be directed into three main directions:
- Covariance: Allows using a type that is a subtype of the specified type in the generic. Denoted by the modifier
out(in Kotlin) or the keywordextends(in Java, for bounded wildcards). It allows only reading from the collection or generic type. - Contravariance: Allows using a type that is a supertype of the specified type in the generic. Denoted by the modifier
in(in Kotlin) or the keywordsuper(in Java, for bounded wildcards). It allows only writing into the collection or generic type. - Invariance: The type must be exactly as specified in the generic. It is used by default in Kotlin and Java. It does not allow using subtypes or supertypes.
Examples:
// Covariance (out)
interface Producer<out T> {
fun produce(): T
}
// Contravariance (in)
interface Consumer<in T> {
fun consume(item: T)
}
// Invariance (by default)
interface Container<T> {
fun getItem(): T
fun putItem(item: T)
}
// Covariance (extends - bounded wildcard)
List<? extends Number> covariantList = new ArrayList<Integer>(); // OK
// Contravariance (super - bounded wildcard)
List<? super Integer> contravariantList = new ArrayList<Number>(); // OK
// Invariance (by default)
List<Number> invariantList = new ArrayList<Number>(); // OK
// List<Number> invariantListError = new ArrayList<Integer>(); // Error