Junior
What types of generics do you know?
sobes.tech AI
Answer from AI
Invariant, covariant, and contravariant.
- Invariance: The type
List<A>is not a subtype ofList<B>and vice versa, even ifAis a subtype ofB. The type remains exact. - Covariance (out): Allows using subtypes.
List<A>is a subtype ofList<B>ifAis a subtype ofB. Used for output parameters (return values).
fun foo(list: List<out Number>) {
// Can read from the list (Number, Double, Int, etc.)
val number: Number = list[0]
// Cannot add to the list (unknown what type of elements are expected)
// list.add(1) // Compilation error
}
- Contravariance (in): Allows using supertypes.
List<B>is a subtype ofList<A>ifAis a subtype ofB. Used for input parameters (arguments).
fun foo(comparable: Comparable<in String>) {
// Can pass String (or its supertypes)
val result = comparable.compareTo("hello")
// Cannot get results of type String (unknown what type of result)
// val str: String = comparable.compareTo("world") // Compilation error
}
In Kotlin, these concepts are implemented using out and in annotations on type parameters. In Java, wildcards (? extends for covariance and ? super for contravariance) are used.
| Type | Purpose | Kotlin keyword | Wildcard (Java) | Reading allowed | Writing allowed |
|---|---|---|---|---|---|
| Invariant | Exact type match | No | No | Yes | Yes |
| Covariant | Use of subtypes (producer - "out") | out |
? extends T |
Yes | No |
| Contravariant | Use of supertypes (consumer - "in") | in |
? super T |
No | Yes |