Nested Classes

Java supports nested classes:

class Foo {
  class Bar {
    // TODO good stuff
  }

  Bar bellyUp() {
    return new Bar();
  }

  // TODO even more good stuff
}

Foo.Bar bar = new Foo().bellyUp();

Similarly, Kotlin supports nested classes. But, as with many things in Kotlin, there are some differences between Java’s approach and Kotlin’s.

Simple Nested Classes

You can have a class inside of a class easily enough in Kotlin:

class Foo {
  class Bar {
    fun whatever() {
      println("You were expecting something profound?")
    }

    // TODO add good stuff
  }

  // TODO add even more good stuff
}

fun main() {
  val bar = Foo.Bar()

  bar.whatever()
}

However, this is not quite the same as the Java example above. The default behavior in Kotlin is more akin to Java’s static class:

class Foo {
  static class Bar {
    // TODO good stuff
  }

  // TODO even more good stuff
}

Foo.Bar bar = new Foo.Bar();

An instance of Bar is not tied to any instance of Foo. In many respects, the nested class is only connected to its outer class by name — you might just as easily have:

class Bar {
  // TODO good stuff
}

class Foo {
  // TODO even more good stuff
}

val bar = Bar()

The biggest value of a nested class, over a completely independent class, is that a nested class has access to private values that are in an eligible scope. That would include values held by an object inside of the outer class:

class Foo {
  private object Data {
    const val VALUE = 1
  }

  class Bar {
    fun value() = Foo.Data.VALUE

    // TODO add good stuff
  }

  // TODO add even more good stuff
}

fun main() {
  val bar = Foo.Bar()

  println(bar.value())
}

Here, Bar can access Foo.Data, even though that object is private, since Bar is nested inside of Foo. Classes and objects outside of Foo have no direct access to Data.

Inner Classes

Let’s go back to the original Java snippet:

class Foo {
  class Bar {
    // TODO good stuff
  }

  Bar bellyUp() {
    return new Bar();
  }

  // TODO even more good stuff
}

Foo.Bar bar = new Foo().bellyUp();

In Java, by default — as in the case with Foo and Bar above — the nested class is an “inner” class. An instance of Bar has access to everything inside of an enclosing instance of Foo.

class Foo {
  int count = 1;

  class Bar {
    int getCount() {
      return count;
    }
  }
}

Foo.Bar bar = new Foo().bellyUp();
int theCount = bar.getCount();

Our instance of Bar has the ability to “reach into” an enclosing instance of Foo and access its members, including fields and methods. In this case, Bar accesses the count field of Foo.

The equivalent in Kotlin requires you to use the inner keyword when declaring the inner class:

class Foo {
  val count = 1

  inner class Bar {
    fun count() = count
  }
}

fun main() {
  val foo = Foo()
  val bar = foo.Bar()

  println(bar.count())
}

An instance of Bar can reference the count inside of the enclosing instance of Foo.

In both Java and Kotlin, only an instance of the outer class can create an instance of the inner class. In our case, we need an instance of Foo to be able to ask it to create for us an instance of Bar. In the case of Kotlin, because creating new objects does not require a keyword, we can just invoke the Bar() constructor on an instance of Foo. In Java, typically we use some method on the outer class to create instances of the inner class for us (e.g., bellyUp()).

Also, to make this work, the instance of the inner class has an implicit reference to the instance of the outer class. We do not have an explicit field for it, but it is there. This causes garbage collection problems, as developers sometimes forget that a Bar has a hidden reference to a Foo, and therefore the Foo cannot be garbage-collected while we are holding onto a Bar.

Which this is this?

Inner classes raise a thorny problem: when we use this, what instance is it referring to?

By default, this refers to the instance of the inner class, so this code prints class Bar or class Foo$Bar, depending on what Kotlin platform you run on:

class Foo {
  inner class Bar {
    fun that() = this
  }
}

fun main() {
  val foo = Foo()
  val bar = foo.Bar()

  println(bar.that()::class)
}

($ notation indicates an inner class relationship, and Foo$Bar means “the Bar class that is an inner class of Foo”, but this will only be seen in Kotlin/JVM, not the Kotlin/JS that Klassbook uses)

In other words, this by default refers to the instance of the inner class (Bar, in this case).

Occasionally, though, we need to specifically get a reference to the instance of the outer class. Android Java developers run into this frequently:

Java has syntax to reaching the outer class instance:

Kotlin has the same concept, with different syntax:

class Foo {
  val count = 1

  inner class Bar {
    fun count() = count

    fun that() = this

    fun theOuterThis() = this@Foo
  }
}

fun main() {
  val foo = Foo()
  val bar = foo.Bar()

  println(bar.that()::class)
  println(bar.theOuterThis()::class)
}

This snippet prints something like:

class Bar
class Foo

this@Foo returns a Foo, specifically the instance of Foo that created the Bar instance on which we called theOuterThis().


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.