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:

https://pl.kotl.in/m6IdDKUXm

Join the Conversation

2 Comments

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: