Generic Classes
In this page:
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
// 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}")
}
Login to try C/C++/Java/PHP code in the editor
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
// 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}")
}
Login to try C/C++/Java/PHP code in the editor
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
// 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())
}
Login to try C/C++/Java/PHP code in the editor
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
// 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())
}
Login to try C/C++/Java/PHP code in the editor
- Writing a separate class for every type it needs to hold (e.g.
IntBox,StringBox) instead of one genericBox<T>. - Forgetting to specify the type argument when it cannot be inferred, such as creating an empty generic collection with no elements to infer from.
- Confusing the type parameter name (like
T) with an actual type;Tis just a placeholder name, conventionally a single capital letter.
- 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
Tacts 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: