In Kotlin, classes can be declared inside other classes in two main ways:
- Nested classes — default behavior
- Inner classes — declared with the
innerkeyword
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.
