Generics
Kotlin is a modern, concise language whose generics let you write one class or function that works safely with any type — the same machinery behind List , Map , and Set .
Learn Generics in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
By the end of this lesson you'll write generic classes and functions, add type constraints, and understand variance at a high level.
What You'll Learn in This Lesson
1️⃣ Generic Classes and Functions
A type parameter in angle brackets, like , is a placeholder for a real type supplied when the generic is used. The compiler tracks it, so a Box Int returns an Int — no casts needed.
Notice the compiler inferred T from the arguments — you rarely have to write the type explicitly.
2️⃣ Constraints and a Generic Stack
An upper bound like restricts T to types you can compare, unlocking operators like . A generic Stack T shows how one reusable type works for strings, numbers, or anything else.
The same maxOf compared both numbers and strings, because both are Comparable . Write it once, reuse it everywhere.
Your turn. Replace the TODO , then run and compare.
Write generic functions with one and two type parameters and call them with different types.
📋 Quick Reference — Generics
Practice quiz
What does a type parameter like <T> represent?
- A fixed type that is always Int
- A placeholder for a real type supplied per use
- A runtime null value
- A reserved keyword for objects
Answer: A placeholder for a real type supplied per use. <T> is a placeholder filled in with a real type when the generic is used.
How is a generic function declared in Kotlin?
- fun firstOf<T>(...)
- fun firstOf(...)<T>
- fun <T> firstOf(...)
- generic fun firstOf(...)
Answer: fun <T> firstOf(...). The type parameter comes before the function name: fun <T> firstOf(...).
In Box(42), how does the compiler know T is Int?
- By type inference from the argument
- It defaults to Any
- You must always write Box<Int>
- It guesses randomly
Answer: By type inference from the argument. The compiler infers T = Int from the constructor argument 42.
What does the upper bound <T : Comparable<T>> guarantee?
- T is always a String
- T can be null
- Values of T can be compared with < and >
- T has no methods
Answer: Values of T can be compared with < and >. The bound guarantees T implements Comparable, so comparison operators work.
Which naming convention is typically used for a map's key and value parameters?
- X and Y
- A and B
- T and E
- K and V
Answer: K and V. K and V are the conventional names for key and value type parameters.
What is the main benefit of generics over using Any?
- They run faster at startup
- They preserve compile-time type safety without casts
- They allow null everywhere
- They remove the need for functions
Answer: They preserve compile-time type safety without casts. Generics keep full type safety, so no casting is needed unlike with Any.
How many type parameters can a generic function declare?
- Exactly one
- At most two
- One or more, such as <K, V>
- None
Answer: One or more, such as <K, V>. A function can declare multiple type parameters, e.g. fun <K, V> pairUp(...).
Why is Kotlin's List declared as List<out E>?
- To make it mutable
- To make it covariant (a producer)
- To forbid reading elements
- To require explicit casts
Answer: To make it covariant (a producer). out makes List covariant, so a List<String> works where List<Any> is wanted.
When the compiler can't infer T, how do you supply it?
- Use Any instead
- Cast the result
- Add a semicolon
- Provide it explicitly, like Box<String>("hi")
Answer: Provide it explicitly, like Box<String>("hi"). Supply the type argument explicitly when inference fails.
What does 'in T' (contravariance) mark a type parameter as?
- A consumer position
- A producer position
- An invariant position
- A nullable position
Answer: A consumer position. in marks a consumer position — the type only accepts T as input.