Kotlin Nested & Inner Classes
Organizing classes within classes for better structure
🏠 What are Nested & Inner Classes?
Nested classes are classes defined inside other classes for better organization. Inner classes can access outer class members, while nested classes are static-like. Both help group related functionality and improve code structure and encapsulation.
// Nested class example
class Outer {
class Nested {
fun greet() = "Hello from nested!"
}
}
Key Concepts
Nested Classes
Static-like classes inside other classes
class Outer {
class Nested {
fun hello() = "Hi!"
}
}
Inner Classes
Can access outer class members
class Outer {
private val name = "Outer"
inner class Inner {
fun getName() = name
}
}
Anonymous Classes
Classes without explicit names
val obj = object : Interface {
override fun method() = "Anonymous"
}
Local Classes
Classes defined inside functions
fun createLocal() {
class Local {
fun greet() = "Local class"
}
}
🔹 Nested Classes
Nested classes don't have access to outer class instance:
class Computer {
private val brand = "Dell"
class Processor {
val cores = 4
val speed = "3.2 GHz"
fun getInfo(): String {
// Cannot access 'brand' here
return "Processor: $cores cores at $speed"
}
}
fun getComputerInfo(): String {
val processor = Processor()
return "Brand: $brand, ${processor.getInfo()}"
}
}
fun main() {
// Create nested class without outer instance
val processor = Computer.Processor()
println(processor.getInfo())
// Create outer class and use nested class
val computer = Computer()
println(computer.getComputerInfo())
}
Output:
Processor: 4 cores at 3.2 GHz
Brand: Dell, Processor: 4 cores at 3.2 GHz
🔹 Inner Classes
Inner classes can access outer class members and need outer instance:
class House {
private val address = "123 Main St"
private val rooms = mutableListOf<String>()
inner class Room(private val name: String) {
fun addToHouse() {
// Can access outer class members
rooms.add(name)
println("Added $name to house at $address")
}
fun getHouseAddress() = address
}
fun addRoom(roomName: String) {
val room = Room(roomName)
room.addToHouse()
}
fun listRooms() {
println("Rooms in house: ${rooms.joinToString(", ")}")
}
}
fun main() {
val house = House()
house.addRoom("Living Room")
house.addRoom("Kitchen")
house.listRooms()
// Create inner class with outer instance
val bedroom = house.Room("Bedroom")
println("House address: ${bedroom.getHouseAddress()}")
}
Output:
Added Living Room to house at 123 Main St
Added Kitchen to house at 123 Main St
Rooms in house: Living Room, Kitchen
House address: 123 Main St
🔹 Anonymous Inner Classes
Create classes on-the-fly using object expressions:
interface ClickListener {
fun onClick()
fun onDoubleClick()
}
class Button {
private var listener: ClickListener? = null
fun setClickListener(listener: ClickListener) {
this.listener = listener
}
fun click() {
listener?.onClick()
}
fun doubleClick() {
listener?.onDoubleClick()
}
}
fun main() {
val button = Button()
// Anonymous inner class
button.setClickListener(object : ClickListener {
override fun onClick() {
println("Button clicked!")
}
override fun onDoubleClick() {
println("Button double-clicked!")
}
})
button.click()
button.doubleClick()
}
Output:
Button clicked!
Button double-clicked!
🔹 Local Classes
Classes defined inside functions can access local variables:
fun createCalculator(operation: String): Any {
val operationName = operation.uppercase()
// Local class
class Calculator {
fun add(a: Int, b: Int): String {
// Can access local variables
return "$operationName: ${a + b}"
}
fun multiply(a: Int, b: Int): String {
return "$operationName: ${a * b}"
}
}
return Calculator()
}
fun main() {
val addCalculator = createCalculator("addition") as Calculator
val multiplyCalculator = createCalculator("multiplication") as Calculator
// Note: This is a simplified example
// In practice, you'd use interfaces or sealed classes
println("5 + 3 = ${addCalculator.add(5, 3)}")
println("4 * 6 = ${multiplyCalculator.multiply(4, 6)}")
}
🔹 Practical Example: Data Structure
Using nested and inner classes to build a linked list:
class LinkedList<T> {
private var head: Node<T>? = null
private var size = 0
// Nested class for Node
class Node<T>(val data: T) {
var next: Node<T>? = null
}
// Inner class for Iterator
inner class Iterator {
private var current = head
fun hasNext(): Boolean = current != null
fun next(): T? {
val data = current?.data
current = current?.next
return data
}
}
fun add(data: T) {
val newNode = Node(data)
newNode.next = head
head = newNode
size++
}
fun iterator(): Iterator = Iterator()
fun getSize(): Int = size
}
fun main() {
val list = LinkedList<String>()
list.add("Third")
list.add("Second")
list.add("First")
println("List size: ${list.getSize()}")
val iterator = list.iterator()
print("Elements: ")
while (iterator.hasNext()) {
print("${iterator.next()} ")
}
}
Output:
List size: 3
Elements: First Second Third