skip to content

Generic Classes & Interfaces

Declaring class Box<T> or an interface with several parameters like Map<K, V>, and using those parameters across members and properties. It is the foundation for every variance question that follows.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

How do you declare a generic class in Kotlin, such as a simple Box<T> that holds a value of type T, and how do you create an instance of it?

level: juniorimportance: must knowfreq 70%

answer

  1. Type param in <> after the class name
  2. No `new` — call the constructor like a function
  3. Inference fills in T from the argument
  4. T usable in properties, params, return types
  5. Erasure: can't do T() or is T

basics

~10 s

Put a type parameter in angle brackets after the class name: class Box<T>(val value: T). Then create it like Box(42) or Box<String>("hi"); Kotlin usually infers the type for you.

solid answer

~40 s

Declare the type parameter in angle brackets right after the class name: `class Box<T>(val value: T)`. `T` is a placeholder that becomes a concrete type per instance. You reference `T` in the constructor, properties, and methods. Construct with `Box(42)` — the compiler infers `T = Int` from the argument — or state it explicitly: `Box<String>("hi")`. Unlike Java, Kotlin has no `new` keyword. A common gotcha: you cannot write `class Box<T>(val value: T = T())` to default-construct a `T`, because `T` is erased at runtime and the compiler has no constructor for an unknown type. Type parameters are conventionally single uppercase letters (`T`, `E`, `K`, `V`) but can be any valid identifier.

code

kotlin · 10 lines
kotlin
class Box<T>(val value: T) {
    fun get(): T = value
}

fun main() {
    val ints = Box(42)             // Box<Int>
    val text = Box<String>("hi")  // explicit
    println(ints.get())            // 42
    println(text.get())            // hi
}

go deeper

for a junior

Knows the class Box<T>(...) syntax, that there's no new, and that the type is usually inferred.

for a middle

Explains where T can appear (properties, params, returns) and that all uses share one concrete type per instance.

for a senior

Brings up erasure: why T()/is T don't work and how a factory or value argument fixes it.

for a principal

Frames API design trade-offs — when to make a class generic vs. accept Any, and how erasure shapes the public surface.

## What a generic class is A **generic class** is a class parameterized by one or more **type parameters** — placeholders for a type that the caller fills in. This lets one class work safely with many element types without casting or `Any`. ## Syntax The type parameter list goes in angle brackets **immediately after the class name**: ```kotlin class Box<T>(val value: T) { fun get(): T = value fun isSame(other: T): Boolean = value == other } ``` - `T` is the **type parameter** (a name; `T` is just convention). - Inside the class body you may use `T` as a property type, parameter type, or return type. - The angle-bracket form `<T>` is the **declaration**; at the use site `Box<Int>` is a **type argument**. ## Creating instances — no `new` Kotlin has no `new` keyword. You call the constructor like a function: ```kotlin val a = Box(42) // T inferred as Int val b = Box<String>("hi") // T given explicitly val c: Box<Long> = Box(7L) // inferred from context ``` Type **inference** fills in `T` from the constructor argument or the expected type, so explicit `<...>` is usually optional. ## Referencing T across members `T` can appear anywhere a type is expected inside the class — in `val`/`var` properties, function parameters, and return types. All uses of `T` in one instance refer to the **same** concrete type. ## A key limitation: erasure Kotlin uses **type erasure** (inherited from the JVM): at runtime `Box<Int>` and `Box<String>` are the same raw `Box`. Therefore you **cannot** do `T()` to construct a `T`, call `T::class`, or use `is T` inside an ordinary class — there is no runtime type info for `T`. You must pass a value or a factory in instead. ## Conventional names `T` (type), `E` (element), `K`/`V` (key/value), `R` (result). Any identifier is legal, but stick to convention for readability.

  • Why can't you write `class Box<T>(val value: T = T())`?
    Type parameters are erased at runtime, so the compiler has no constructor for the unknown type `T`. You must pass a value or a factory function instead.
  • Does Kotlin need the `new` keyword to instantiate a generic class?
    No. Kotlin has no `new`; you call the constructor like a regular function, e.g. `Box(42)`.

A generic class is a labeled shipping box: the same box design carries anything, and the label (type argument) records what's inside so you can't pull out the wrong thing.

saying these in an interview costs you the question

  • Putting the type parameter after the constructor parentheses instead of after the class name
  • Using `new Box<Int>(...)` (Java syntax) in Kotlin
  • Claiming you can default a property with `T()` inside the class
  • Thinking each property could have a different concrete T within one instance

context

open as a page

How do you declare a class or interface with multiple type parameters, like Map<K, V>, and reference those parameters across the members?

level: middleimportance: must knowfreq 60%

basics

~10 s

List the parameters comma-separated in angle brackets: class Pair<K, V>(val key: K, val value: V). Each name is its own placeholder, and you can use both anywhere a type is needed inside the class.

open as a page

How can a class implement a generic interface, and what choices do you have for the interface's type parameter when you do?

level: middleimportance: should knowfreq 45%

basics

~10 s

When a class implements a generic interface, it either fixes the type argument to a concrete type (class IntBox : Container<Int>) or stays generic and forwards its own parameter (class Box<T> : Container<T>).

open as a page

When referencing a type parameter T across a generic class's members, what is the default upper bound of an unbounded T, and how do star projections (Box<*>) relate to instances of a generic class?

level: seniorimportance: should knowfreq 40%

basics

~20 s

An unbounded T defaults to the nullable top type Any?, so T can be null unless you constrain it. Box<*> is a star projection — a Box of some unknown type you can read from safely but can't pass specific values into.

open as a page

The standard library declares Comparable<in T> and Iterable<out T>. What do the `in` and `out` modifiers on a generic interface's type parameter mean, and why are they placed where they are?

level: seniorimportance: should knowfreq 55%

basics

~10 s

out means T is only produced (returned), so the interface is covariant — Iterable<Cat> is an Iterable<Animal>. in means T is only consumed (passed in), so it's contravariant — Comparable<Animal> is a Comparable<Cat>.

open as a page