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.

Create a free account to save this page, take notes and track your progress. Sign in

Generic classes and functions

Type parameters go in angle brackets. <T : Comparable<T>> adds an upper bound.

Generic classes and bounds
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 a Box<Cat> can be used as a Box<Animal>. List<out E> is why a List<String> is a List<Any>.
  • in T (contravariant): the type only consumes T.
  • inline fun <reified T> keeps the type at runtime, so you can check is T (generics are otherwise erased).
Covariance and reified type parameters
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?

  1. T is nullable
  2. The class only produces T, so it's covariant
  3. T is private
  4. The class only consumes T
Show answer

Answer: The class only produces T, so it's covariant

Was this page helpful?