← Back to Kotlin Course | Chapter 11: Generics | Lesson 1 of 6

Generic Classes

A generic class is a container blueprint that leaves a blank for 'what type of thing goes inside', to be filled in later.
Syntax
kotlin
class ClassName<T>(val item: T) {
    fun get(): T = item
}

val a = ClassName(value)               // T inferred
val b = ClassName<Type>(value)         // explicit type argument

Declaring a Generic Class

A type parameter in angle brackets, like <T>, after the class name lets that class work with any type, filled in as T wherever it's used inside.

Example: Declaring a Generic Class

markup
// Define a class `Box`
class Box<T>(val item: T)

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `intBox`, set to `Box(42)`
    val intBox = Box(42)
    // Declare a read-only variable `stringBox`, set to `Box("Kotlin")`
    val stringBox = Box("Kotlin")
    // Print "${intBox.item}, ${stringBox.item}" to the console, with a trailing newline
    println("${intBox.item}, ${stringBox.item}")
}

Type Inference for Generics

Kotlin usually infers the type argument automatically from the value passed to the constructor, so you rarely need to write Box<Int> explicitly.

Example: Type Inference for Generics

markup
// Define a class `Pair2`
class Pair2<A, B>(val first: A, val second: B)

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `pair`, set to `Pair2("age", 30)`
    val pair = Pair2("age", 30)
    // Print "${pair.first} = ${pair.second}" to the console, with a trailing newline
    println("${pair.first} = ${pair.second}")
}

Explicit Type Arguments

When there is nothing for the compiler to infer from, such as creating an empty generic container, the type argument must be provided explicitly in angle brackets.

Example: Explicit Type Arguments

markup
// Define a class `Container`
class Container<T> {
    private val items = mutableListOf<T>()
    fun add(item: T) = items.add(item)
    // Define the function `all` with no parameters and returning a `List<T>`
    fun all(): List<T> = items
}

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `container`, set to `Container<String>()`
    val container = Container<String>()
    // Add `"Kotlin"` to `container`
    container.add("Kotlin")
    // Add `"Generics"` to `container`
    container.add("Generics")
    // Print `container.all()` to the console, with a trailing newline
    println(container.all())
}

Multiple Type Parameters

A generic class can declare more than one type parameter, letting it work with several independent placeholder types at once.

Example: Multiple Type Parameters

markup
// Define a class `KeyValue`
class KeyValue<K, V>(val key: K, val value: V) {
    fun describe() = "$key -> $value"
}

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `entry`, set to `KeyValue("name", "Kotlin")`
    val entry = KeyValue("name", "Kotlin")
    // Print `entry.describe()` to the console, with a trailing newline
    println(entry.describe())
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Writing a separate class for every type it needs to hold (e.g. IntBox, StringBox) instead of one generic Box<T>.
  2. Forgetting to specify the type argument when it cannot be inferred, such as creating an empty generic collection with no elements to infer from.
  3. Confusing the type parameter name (like T) with an actual type; T is just a placeholder name, conventionally a single capital letter.
Chapter Summary
  • A generic class declares one or more type parameters in angle brackets after its name, such as class Box<T>(val item: T).
  • The type parameter T acts as a placeholder that gets replaced with a concrete type when the class is used.
  • Type arguments are often inferred automatically from constructor arguments, but can be specified explicitly when needed.
  • Generic classes avoid duplicating the same logic for every different type it might need to hold.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.