How do I use inner and nested classes in Kotlin?

In Kotlin, classes can be declared inside other classes in two main ways:

  1. Nested classes — default behavior
  2. Inner classes — declared with the inner keyword

Nested classes

A class declared inside another class is nested by default.

class Outer {
    class Nested {
        fun message(): String {
            return "Hello from Nested"
        }
    }
}

You create an instance of the nested class using the outer class name:

fun main() {
    val nested = Outer.Nested()
    println(nested.message())
}

Important point

A nested class does not have access to members of the outer class.

class Outer {
    private val name = "Outer"

    class Nested {
        fun printName() {
            // println(name) // Error: cannot access outer class member
        }
    }
}

This is similar to a static nested class in Java.


Inner classes

If you want the nested class to access members of the outer class, mark it with inner.

class Outer {
    private val name = "Outer"

    inner class Inner {
        fun message(): String {
            return "Hello from $name"
        }
    }
}

You create an inner class instance from an instance of the outer class:

fun main() {
    val outer = Outer()
    val inner = outer.Inner()

    println(inner.message())
}

Output:

Hello from Outer

Difference between nested and inner classes

Feature Nested class Inner class
Keyword No keyword needed Uses inner
Has reference to outer class No Yes
Can access outer members No Yes
Instantiation Outer.Nested() Outer().Inner()
Similar to Java static nested class non-static inner class

Accessing this from an inner class

Inside an inner class, this refers to the inner class instance.

To refer to the outer class instance, use this@Outer.

class Outer {
    private val value = "Outer value"

    inner class Inner {
        private val value = "Inner value"

        fun printValues() {
            println(value)
            println(this.value)
            println([email protected])
        }
    }
}

Output:

Inner value
Inner value
Outer value

Example with state

class ShoppingCart {
    private val items = mutableListOf<String>()

    fun addItem(item: String) {
        items.add(item)
    }

    inner class Summary {
        fun printSummary() {
            println("Cart has ${items.size} items")
            println(items.joinToString())
        }
    }
}

fun main() {
    val cart = ShoppingCart()
    cart.addItem("Book")
    cart.addItem("Pen")

    val summary = cart.Summary()
    summary.printSummary()
}

Output:

Cart has 2 items
Book, Pen

Here, Summary is an inner class because it needs access to items from ShoppingCart.


When to use each

Use a nested class when:

  • The class is logically grouped inside another class
  • It does not need access to the outer class instance
  • You want a namespace-like structure
class ApiResponse {
    class Error(val code: Int, val message: String)
}

Use an inner class when:

  • The class needs access to the outer class’s properties or functions
  • Each inner class instance is tied to a specific outer class instance
class Form {
    private val fields = mutableListOf<String>()

    inner class Validator {
        fun validate(): Boolean {
            return fields.isNotEmpty()
        }
    }
}

Summary

class Outer {
    class Nested {
        // No access to Outer instance
    }

    inner class Inner {
        // Has access to Outer instance
    }
}

Use nested classes by default, and use inner only when the inner class needs to access the outer class instance.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.