Kotlin Nested and Inner classes

1. Overview

In this article, we will discuss the Kotlin nested and inner classes. Sometimes we need to group classes and interfaces in one place to create more readable and maintainable code. It increases the use of encapsulation by enabling us to hide the data in a single entity to protect it from outside access.

2. Nested class Kotlin

We can nest classes in other classes.

For example, the class Student has a nested class Subject. We also have a subjectFunc function in the Subject class. The below code will work fine as Kotlin allows you to declare a class inside another class.

class Student {
    private val studentId: Int = 1
    class Subject {
        fun subjectFunc() = "Nested function"
    }
}
fun main() { 
    println(Student.Subject().subjectFunc())
}

Suppose you want to access and instantiate your nested class from outside class or the main function. How to do it? You can access your nested class only through your outer class.

The syntax for instantiating the nested class is:

OuterClassName.NestedClassName()

Note the outer class name with a dot at the starting before your nested class instantiation. In the above example, Student.Subject() creates an instance of the Subject class, and then you can access its members using the instance.

2.1. Nestes Interfaces

You can also nest your interfaces in other classes and interfaces. Let’s take an example.

In the below code, the Outer class contains an interface OnClickInterface that also holds another interface OnProcessInterface.

class Outer {
    private val outerVariable: Int = 1
    interface OnClickInterface  {
        fun click()
        interface OnProcessInterface {
            fun process()
        }
    }
    class Nested : OnClickInterface {
        override fun click() {
            println("Click")
        }
    }
}

You can nest interfaces in classes, classes in interfaces, and interfaces in interfaces.

interface OuterInterface {
    class NestedClass
    interface NestedInterface
}
class OuterClass {
    class NestedClass
    interface NestedInterface
}

3. Inner class Kotlin

You can mark the nested class as the Inner class using the keyword Inner. The syntax to access the inner class is:

OuterClass().InnerClass()

3.1. Kotlin inner class access outer variable

Sometimes we will need to access the outer class members from the nested class. But Nested class can’t access the outer class members.

For example, the below Nested class can’t access your Outer class variable foo.

class Outer {
    val foo: Int = 1
        class Nested {
           fun print() {
              println(foo) 
           }
        }
}
fun main() {
    Outer.Nested().print()
}

You can access the outer class members if you declare your nested class as Inner class. To put it in another way, a nested class marked as inner can access the members of its outer class by holding a reference to the outer class object.

The below code throws the error “Constructor of inner class Nested can be called only with receiver of containing class” as you call the Nested class without the outer class instance.

class Outer {
    val foo: Int = 1
        inner class Nested {
           fun print() {
            println(foo)
           }
        }
}
fun main() {
    Outer.Nested().print() 
}

Makes little sense? No worries. Let’s see the below code that will work. We access the nested class using the instance of the outer class. Therefore, the nested class can access all the outer class members.

class Outer {
    val foo: Int = 1
        inner class Nested {
           fun print() {
            println(foo)
           }
        }
}
fun main() {
    Outer().Nested().print()
}

3.2. Qualified this

Suppose you have the same variable name in both outer and inner classes. The inner class variable takes precedence over the outer class variable inside the inner class.

For example, both the Student and Subject classes have the same variable name. The print function in the Subject class displays the subject name.

class Student {
    val name: String = "John"
        inner class Subject {
            val name: String = "Maths"
           fun print() {
            println(name)
           }
        }
}
fun main() {
    Student().Subject().print() 
}

What if you want to print Student‘s name instead of Subject ‘s name. You can do it using the qualified this. The This with qualifier label enables us to point to the scope we want. In the this@label, where @label is a label on the scope this is meant to be from. The implicit label for the scope would be the class or function name.

For example, the Student class has an implicit label @Student (its class name), so this@Student refers to the outer class scope. The same way Subject class has an implicit label @Subject therefore this@Subject refers to the inner class Subject scope.

this@Student.name will refer to the Student class member name. If this has no qualifiers, it refers to the innermost enclosing scope. Therefore, this.name refers to the Subject class which is the innermost enclosing scope.

class A { 
    val foo: Int = 1
    inner class B { 
        val foo:Int = 2
        fun print() { 
            println(this@A.foo) 
            println(this@B.foo) 
            println(foo) 
        }
    }
}
fun main() {
    A().B().print() 
}

4. Conclusion

In this article, we have learned about the Kotlin Nested and Inner classes.

See our Kotlin articles to know other topics.

Leave a Comment