Introduction
Many programming languages allow us to declare nested classes, that is, having a class definition inside another. This approach may come in handy for several scenarios: apply the SRP, provide higher encapsulation or simply have a better structured code.
class ExternalClass {
//XXX: props and methods for main class...
class InternalClass {
//XXX: props and methods for nested class...
}
}
Both Java and Kotlin support nested classes, but there are some important differences that are worth keeping in mind. Let’s review them.
Inner classes in Java
In Java, nested classes declare (implicitly) a reference to the surrounding class.
Nested classes are commonly used when working with view states, so let’s declare a class “Button” and its corresponding nested class “ButtonState“:
/**
* Abstraction for button objects
*/
class Button {
//XXX: used to store encapsulated state
protected ButtonState state;
public Button() {
//XXX: initialization here...
}
/**
* Abstraction for button state
*/
class ButtonState {
boolean enabled;
String hint;
ButtonState() {
//XXX: initialization here...
}
void accessOuterClass() {
Log.d("ButtonState", "current state is" +
Button.this.state);
}
}
}
So, as we said before, in this case internal classes always have direct access to external scope. Although this may be useful sometimes, it is a common source of errors too: we can easily bump into memory leaks, exceptions when applying serialization, etc.
If we want to remove the default implicit reference, then we have to declare the class as static using the corresponding modifier:
class Button {
//XXX: methods and props
static class ButtonState {
//XXX: methods and props
}
}
Inner classes in Kotlin
On the other hand, nested classes in Kotlin do not declare any implicit reference to surrounding classes. So they could be considered safer by default: by removing this reference, we get rid of possible memory leaks and other errors automatically.
/**
* Outer class for button abstraction as an example
*/
class Button(var state = State()) {
/**
* Inner class used to store the state of the outer button class
*/
class State(val text : String = "Click me", val enabled : Boolean = true) {
/**
* Access props declared in the external class.
*/
fun accessOuterClass() {
//TODO: wont work right now!
}
}
}
But then, what do we do if we need to access the external class? We have to apply the inner modifier in the nested class declaration:
class Button() {
inner class State(val text : String = "Click me", val enabled : Boolean = true) {
/**
* Access props declared in the external class.
*/
fun accessOuterClass() {
Log.d("ButtonState", "state is ${this@Button.state})
}
}
}
Wrapping up
Inner classes in both programming languages have the same semantics, but they behave in a different way: in Java, nested classes have access by default to external classes. On the contrary, Kotlin classes do not have it, so we apply the inner modifier to get the “default Java behaviour”.
Check a small code sample to play with in the following link: