English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Kotlin Inheritance

In this article, you will learn about inheritance. More specifically, what is inheritance and how to implement it in Kotlin using inheritance (with examples).

Inheritance is one of the key features of object-oriented programming. It allows users to create a new class (derived class) from an existing class (base class).

Derived classes inherit all the functions of the base class and can have their own other functions.

Before going into the details of Kotlin inheritance, it is recommended that you read the following two articles:

Why inheritance?

Suppose you need three roles in your application-amath teacher(MathTeacher), afootball player(Footballer) and aBusinessman.

Since all roles are people, they can walk and talk. However, they also have some special skills. A math teacher canteach math (teachMath), and a football player canplay football(playFootball), a businessman canrunBusiness.

You can create three separate classes that can walk, talk, and perform their special skills.

You will copy the same walking and talking code for each role in each class.

If you want to add new features - For eating (eat), you need to implement the same code for each role. This can easily lead to errors (during copying) and repetitive code.

If we have a Person class with basic functions, such as walking, eating, and sleeping, and add special skills for these functions according to our roles, it would be much easier. This is done through inheritance.

With inheritance, you no longer need to implement the same walk(), talk(), and eat() code for each class. You just needInheritanceThat's all.

Therefore, for MathTeacher (derived class), you can inherit all the functions of Person (base class) and add a new function teachingMath(). Similarly, for Footballer class, you inherit all the functions of Person class and add a new function playFootball(), and so on.

This makes your code more concise, understandable, and extensible.

It is important to remember that:When dealing with inheritance, each derived class should meet the condition of whether it is a 'base' class. In the above example, MathTeacher is a Person (person), and Footballer is a Person (person). You cannot think that 'Businessman' is the same as 'Business'.

Kotlin inheritance

Let's try to implement the above discussion in the code:

open class Person(age: Int) {
    //Code for eating, speaking, and walking
}
class MathTeacher(age: Int): Person(age) {
    //Other characteristics of the math teacher
}
class Footballer(age: Int): Person(age) {
    //Other characteristics of the footballer
}
class Businessman(age: Int): Person(age) {
    // Other characteristics of the businessman
}

Here, Person is the base class, and the MathTeacher, Footballer, and Businessman classes are derived from the Person class.

Note that the keyword open is very important before the base class Person.

By default, classes in Kotlin are final. If you are familiar with Java, you will know that final classes cannot be subclassed. By using the annotation on a class, the compiler allows you to derive new classes from it.

Example: Kotlin inheritance

open class Person(age: Int, name: String) {
    init {
        println("My name is $name.")
        println("My age is $age")
    }
}
class MathTeacher(age: Int, name: String): Person(age, name) {
    fun teachMaths() {
        println("I teach in an elementary school.")
    }
}
class Footballer(age: Int, name: String): Person(age, name) {
    fun playFootball() {
        println("I play for Los Angeles Galaxy.")
    }
}
fun main(args: Array<String>) {
    val t1 = MathTeacher(25, "Jack")
    t1.teachMaths()
    println()
    val f1 = Footballer(29, "Christiano")
    f1.playFootball()
}

The output when running the program is:

My name is Jack.
My age is 25
I teach in an elementary school.
My name is Cristiano.
My age is 29
I play for Los Angeles Galaxy.

Here, two classes, MathTeacher and Footballer, are derived from the Person class.

The main constructor of the Person class declares two properties: age and name, and has an initialization block. Objects of the derived Person classes (MathTeacher and Footballer) can access the initialization block (and member functions) of the base class.

The derived classes MathTeacher and Footballer have their own member functions teachMaths() and playFootball(). These functions can only be accessed from objects of their respective classes.

When creating an object of the MathTeacher class t1 When

val t1 = MathTeacher(25, "Jack")

Parameters are passed to the primary constructor. In Kotlin, when an object is created, the init block is called. Since MathTeacher is derived from the Person class, it will look for and execute the initialization block in the base class (Person). If MathTeacher has an init block, the compiler will also execute the init block of the derived class.

Next, use t1.teachMaths() statement calls the object t1The teachMaths() function.

Creates an object of the class f1 When, the working principle of the program is similar. It executes the init block of the base class. Then, the statement f1.playFootball() calls the playFootball() method of the Footballer class.

Important note: Kotlin inheritance

  • If the class has a primary constructor, the base class must be initialized using the parameters of the primary constructor. In the above program, both derived classes have two parameters age and name, and both parameters are initialized in the primary constructor of the base class.
    Here is another instance:

    open class Person(age: Int, name: String) {
        // some code
    }
    class Footballer(age: Int, name: String, club: String): Person(age, name) {
        init {
            println("The football player named $name, aged $age, plays for $club.")
        }
        fun playFootball() {
            println("I am playing football.")
        }
    }
    fun main(args: Array<String>) {
        val f1 = Footballer(29, "Cristiano", "LA Galaxy")
    }

      In this case, the main constructor of the derived class has3parameters, while the base class has2parameters. Please note that both parameters of the base class have been initialized.

  • If there is no primary constructor, each base class must initialize the base class (using the super keyword) or delegate to another constructor that performs this operation. For example

    fun main(args: Array<String>) {
        val p1 = AuthLog("Bad Password")
    }
    open class Log {
        var data: String = ""
        var numberOfData = 0
        constructor(_data: String) {
        }
        constructor(_data: String, _numberOfData: Int) {
            data = _data
            numberOfData = _numberOfData
            println("$data: $numberOfData times")
        }
    }
    class AuthLog: Log {
        constructor(_data: String): this("From AuthLog -> + $_data", 10) {
        }
        constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
        }
    }

      For more information on how the program works, please visitKotlin secondary constructor.

Overriding member functions and properties

If the base class and derived class contain member functions (or properties) with the same name, it may be necessary to use the override keyword to override the derived class member functions, and use the open keyword for the base class member functions.

Example: Overriding member functions

// Empty primary constructor
open class Person() {
    open fun displayAge(age: Int) {
        println("My age is $age.")
    }
}
class Girl: Person() {
    override fun displayAge(age: Int) {}}
        println("My virtual age is ${age - 5}.")
    }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

The output when running the program is:

The virtual age is 26.

Here, girl.displayAge(31) Call the displayAge() method of the derived class Girl.

You can override the base class properties in a similar way.

Before learning the following examples, you can visit Kotlin's Getters and Setters Check how it works.

//Empty primary constructor
open class Person() {
    open var age: Int = 0
        get() = field
        set(value) {
            field = value
        }
}
class Girl: Person() {
    override var age: Int = 0
        get() = field
        set(value) {
            field = value - 5
        }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.age = 31
    println("My virtual age is ${girl.age}.")
}

The output when running the program is:

My virtual age is 26.

As you can see, we use the override and open keywords for the age property in the derived class and base class, respectively.

Calling base class members from derived class

You can use the super keyword to call the base class function (and access properties) from the derived class. Here's how to do it:

open class Person() {
    open fun displayAge(age: Int) {
        println("My actual age is $age.")
    }
}
class Girl: Person() {
    override fun displayAge(age: Int) {}}
        //Calling the base class function
        super.displayAge(age)
        
        println("My virtual age is ${age - 5}.")
    }
}
fun main(args: Array<String>) {
    val girl = Girl()
    girl.displayAge(31)
}

The output when running the program is:

My actual age is 31.
My virtual age is 26.