Kotlin Class Types Series – Part 5: Inner & Nested Classes
Rahul Pahuja
Staff Software Engineer @ CyberArk | Expertise in Android , iOS Development | MVC | MVVM | Java | Kotlin | Swift | Unit Testing | Automation Testing using Python and Appium | Bits Pilani Alum
Welcome to Part 5 of our Kotlin class types series! Today, we’re diving into inner and nested classes, exploring how they work, their performance implications, testing challenges, and best practices.
What Are Inner and Nested Classes?
?? Nested Classes
A nested class is a class declared inside another class without the inner keyword. It does not hold a reference to the outer class.
class Outer {
class Nested {
fun greet() = "Hello from Nested!"
}
}
val message = Outer.Nested().greet()
println(message) // Output: Hello from Nested!
Since Nested does not reference Outer, it behaves just like a regular class, making it more memory-efficient.
?? Inner Classes
An inner class is a class declared with the inner keyword. It holds a reference to the outer class, allowing access to its members.
class Outer(val name: String) {
inner class Inner {
fun greet() = "Hello from Inner! Outer name: $name"
}
}
val outer = Outer("Kotlin")
val inner = outer.Inner()
println(inner.greet()) // Output: Hello from Inner! Outer name: Kotlin
Since Inner keeps a reference to Outer, it can access its properties and methods.
? Performance Considerations
? Nested Classes Are More Efficient – Since nested classes don’t keep an implicit reference to the outer class, they consume less memory.
? Inner Classes Enable Better Encapsulation – Inner classes allow better scoping of logic within an enclosing class.
?? Pitfall: Memory Leaks with Inner Classes – Since an inner class holds a reference to the outer class, it can lead to memory leaks in long-lived objects (especially in Android).
?? Do: Use inner classes only when you truly need access to outer class members. ?? Don’t: Use inner classes indiscriminately, as they can introduce unexpected memory retention issues.
?? Testing Challenges
?? Unit Testing Nested Classes: Since nested classes are independent, they can be tested like regular classes.
领英推荐
@Test
fun `nested class function works`() {
val nested = Outer.Nested()
assertEquals("Hello from Nested!", nested.greet())
}
?? Unit Testing Inner Classes: Because inner classes require an instance of the outer class, test setup can be more complex.
@Test
fun `inner class function works`() {
val outer = Outer("Kotlin")
val inner = outer.Inner()
assertEquals("Hello from Inner! Outer name: Kotlin", inner.greet())
}
?? Pitfall: Mocking Complexity – When testing inner classes, you may need to mock the outer class, which can introduce additional complexity.
?? Maintainability & Best Practices
? When to Use Nested Classes
? When to Use Inner Classes
? When to Avoid Inner Classes
?? Dos & Don’ts
? Do: Use nested classes for better encapsulation without unnecessary references. ? Do: Use inner classes only when access to outer members is required. ? Don't: Hold references to the outer class unless necessary. ? Don't: Use inner classes for large objects or objects with long lifetimes.
Final Thoughts
Nested and inner classes serve different purposes in Kotlin. Choosing between them depends on whether the inner class needs access to the outer class.
Next up: Part 6: Sealed Classes, where we’ll explore how they enable better type safety and exhaustive when-expressions in Kotlin! ??
Have you used inner or nested classes in your projects? Share your experiences in the comments! ??