How do nested vs inner classes interact with generics and interface implementations on the outer class? For example, can a nested class implement an interface using the outer's type parameter?
answer
- Outer T is per-instance scoped
- Nested can't see outer T; inner can
- Custom Iterator<T> is usually inner
- Nested must declare its own generics
- companion object can't use outer T either
basics
~20 sA nested class is independent, so it cannot use the outer class's type parameters or instance state. An inner class can, because it is tied to a specific outer instance and shares its generic context.
solid answer
~40 sType parameters declared on the outer class belong to outer **instances**. A plain **nested** class has no enclosing instance, so it cannot reference `T` from `class Outer<T>` — the parameter is simply out of scope; a nested class must declare its own generics. An **inner** class is associated with a concrete `Outer<T>` instance, so its body can use `T` directly (e.g. implement `Iterator<T>` or `Comparator<T>` over the outer's data). This is why custom iterators and view-like helpers over a generic collection are usually `inner`. If you want a nested class to be generic-free yet still work with the outer's data, parameterize the nested class itself or pass values in. Companion objects are a special nested form with their own rules.
code
kotlin · 12 linesclass Box<T>(private val items: List<T>) {
inner class BoxIterator : Iterator<T> {
private var i = 0
override fun hasNext() = i < items.size
override fun next(): T = items[i++]
}
fun iterator(): Iterator<T> = BoxIterator()
}
fun main() {
val it = Box(listOf("a", "b")).iterator()
while (it.hasNext()) println(it.next())
}go deeper
Knows inner classes can use outer data while nested ones cannot.
Understands that the outer's T is unavailable to nested classes and available to inner ones.
Designs a custom Iterator<T> as inner, explains instance-scoped type parameters, and distinguishes companion objects.
Weighs encapsulation vs coupling when exposing inner iterator/view types and reasons about variance and API surface for generic outer types.
## Generics live on the instance For `class Outer<T>`, the type parameter `T` is bound per **instance** of `Outer`. Anything that wants to use `T` needs access to an `Outer<T>` instance. - **Nested class**: no enclosing instance, therefore **no access to `T`**. The compiler reports `T` as unresolved. A nested class can still be generic — but it must declare its **own** parameters. - **Inner class**: tied to an `Outer<T>` instance, so `T` is in scope and usable in supertypes, signatures, and bodies. ```kotlin class Box<T>(private val items: List<T>) { // inner: can use T and the outer's items inner class BoxIterator : Iterator<T> { private var i = 0 override fun hasNext() = i < items.size override fun next(): T = items[i++] } fun iterator(): Iterator<T> = BoxIterator() // nested would NOT compile if it tried to use T: // class Bad : Iterator<T> { ... } // error: T not in scope // a nested class must bring its own parameter: class Pair2<A, B>(val a: A, val b: B) } ``` ## Why iterators are typically inner A custom `Iterator<T>`/`ListIterator<T>` needs both the element type `T` and live access to the backing data (`items`), both of which only an `inner` class gets for free. The same applies to `Comparator<T>` helpers or builder views. ## Implementing interfaces Either kind can implement an interface; the difference is what type arguments and state are available. A nested class can implement `Iterator<String>` (a concrete type) fine — it just can't implement `Iterator<T>` for the outer's `T`. ## Companion objects `companion object` is a nested singleton, not an inner class; it likewise cannot use the outer's per-instance `T`, and there is exactly one per outer class. ## Key takeaways - Outer `T` is instance-scoped → only `inner` classes see it. - Nested classes must declare their own generics. - Custom iterators/comparators over generic outers are naturally `inner`.
- Can a nested class be generic at all?Yes, but it must declare its own type parameters; it cannot borrow the outer class's parameters.
- Why are custom iterators usually declared `inner`?They need both the element type `T` and live access to the backing data, which only an inner class shares with the outer instance.
saying these in an interview costs you the question
- Claiming a nested class can reference the outer's `T`
- Saying inner classes cannot implement interfaces
- Thinking `companion object` can use the outer's per-instance type parameter
- Asserting nested classes can't be generic
- Confusing type-parameter scope with visibility