Kotlin Tutorial · Advanced Kotlin · Lesson 23 of 31
Kotlin Generics
Generic classes and functions, type constraints, variance with in and out, and reified type parameters.
Generic classes and functions
Type parameters go in angle brackets. <T : Comparable<T>> adds an upper bound.
class Stack<T> {
private val items = mutableListOf<T>()
fun push(item: T) = items.add(item)
fun pop(): T? = items.removeLastOrNull()
val size get() = items.size
}
fun <T : Comparable<T>> largest(items: List<T>): T? = items.maxOrNull()
fun main() {
val stack = Stack<String>()
stack.push("a")
stack.push("b")
println("${stack.pop()} ${stack.size}")
println(largest(listOf(3, 9, 4)))
println(largest(listOf("pear", "apple")))
}
Output
b 1 9 pear
Run this on your computer — see “Get Started” for setup.
Variance and reified types
out T(covariant): the type only produces T, so aBox<Cat>can be used as aBox<Animal>.List<out E>is why aList<String>is aList<Any>.in T(contravariant): the type only consumes T.inline fun <reified T>keeps the type at runtime, so you can checkis T(generics are otherwise erased).
open class Animal(val name: String)
class Cat(name: String) : Animal(name)
class Producer<out T>(private val value: T) {
fun get(): T = value
}
fun printName(p: Producer<Animal>) = println(p.get().name)
inline fun <reified T> List<Any>.only(): List<T> = filter { it is T }.map { it as T }
fun main() {
printName(Producer(Cat("Tom"))) // Producer<Cat> is a Producer<Animal>
val mixed: List<Any> = listOf(1, "two", 3.0, "four")
println(mixed.only<String>())
}
Output
Tom [two, four]
Run this on your computer — see “Get Started” for setup.
Test yourself
What does out T on a class's type parameter mean?
T is nullableThe class only produces T, so it's covariantT is privateThe class only consumes T
Show answer
Answer: The class only produces T, so it's covariant