Sobes.tech
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 keyword extends (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 keyword super (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