Kotlin – Inheritance

Inheritance is an important feature of object oriented programming language. Inheritance allows to inherit the feature of existing class (or base or parent class) to new class (or derived class or child class).The main class is called super class (or parent class) and the class which inherits the superclass is called subclass (or child class). The subclass contains features of superclass as well as its own.The concept of inheritance is allowed when two or more classes have same properties. It allows code reusability. A derived class has only one base class but may have multiple interfaces whereas a base class may have one or more derived classes.In Kotlin, the derived class inherits a base class using operator in the class header (after the derive class name or constructor)

open class Base(p: Int){
}
class Derived(p: Int) : Base(p){
}

Suppose that,we have two different classes “Programmer” and “Salesman” having the common properties ‘name’,’age’, and ‘salary’ as well as their own separate functionalitiesdoProgram() and fieldWork(). The feature of inheritance allows that we can inherit (Employee) containing the common features.

open class Employee(name: String, age: Int, salary: Float) {
    // code of employee
}

class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {
    // code of programmer
}

class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {
    // code of salesman
}

All Kotlin classes have a common superclass “Any”. It is a default superclass for a class with no supertypes explicitly specified.For example, a class Example is implicitly inherited from Any.

class Example

open keyword

As Kotlin classes are final by default, they cannot be inherited simply. We use the open keyword before the class to inherit a class and make it to non-final.

For example :

open class Example{
// I can now be extended!
}
  • Kotlin Inheriting fields from a class :

When we inherit a class to derive class, all the fields and functionalities are inherited. We can use these fields and functionalities in derived class.

open class Base{
val x = 10
}
class Derived: Base() {
    fun foo() {
println("x is equal to " + x)
    }
}
fun main(args: Array<String>) {
val derived = Derived()
    derived.foo()
}

Output :

x is equal to 10
  • Kotlin Inheriting methods from a class :
open class Bird {
    fun fly() {
        println("flying...")
    }
}

class Duck : Bird() {
    fun swim() {
        println("swimming...")
    }
}

fun main(args: Array<String>) {
    val duck = Duck()
    duck.fly()
    duck.swim()
}

Output :

flying...
swimming...
  • Example 1 : Here, we declare a class Employee is superclass and Programmer and Salesman are their subclasses. The subclasses inherit properties name, age and salary as well as subclasses containtheir own functionalitieslike doProgram() and fieldWork().
open class Employee(name: String, age: Int, salary: Float) {
    init {
        println("Name is $name.")
        println("Age is $age")
        println("Salary is $salary")
    }
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun doProgram() {
        println("programming is my passion.")
    }
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun fieldWork() {
        println("travelling is my hobby.")
    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Ashu", 25, 40000f)
    obj1.doProgram()
    val obj2 = Salesman("Ajay", 24, 30000f)
    obj2.fieldWork()
}

Output :

Name is Ashu.
Age is 25
Salary is 40000.0
programming is my passion.
Name is Ajay.
Age is 24
Salary is 30000.0
travelling is my hobby.

Inheritance and primary constructor

If the base and derived class both having primary constructor in that case the parameters are initialized in the primary constructor of base class. In above example of inheritance, all classes contain three parameters “name”, “age” and “salary” and all these parameters are initialized in primary constructor of base class.When a base and derived class both contains different numbers of parameters in their primary constructor then base class parameters are initialized form derived class object.For example :

open class Employee(name: String, salary: Float) {
    init {
        println("Name is $name.")
        println("Salary is $salary")
    }
}

class Programmer(name: String, dept: String, salary: Float) : Employee(name, salary) {
    init {
        println("Name $name of department $dept with salary $salary.")
    }

    fun doProgram() {
        println("Programming is my passion.")

    }
}

class Salesman(name: String, dept: String, salary: Float) : Employee(name, salary) {
    init {
        println("Name $name of department $dept with salary $salary.")
    }

    fun fieldWork() {
        println("Travelling is my hobby.")

    }
}

fun main(args: Array<String>) {
    val obj1 = Programmer("Ashu", "Development", 40000f)
    obj1.doProgram()
    println()
    val obj2 = Salesman("Ajay", "Marketing", 30000f)
    obj2.fieldWork()
}

Output :

Name is Ashu.
Salary is 40000.0
Name Ashu of department Development with salary 40000.0.
Programming is my passion.
Name is Ajay.
Salary is 30000.0
Name Ajay of department Marketing with salary 30000.0.
Travelling is my hobby.

When an object of derived class is created, it calls its superclass first and executes init block of base class followed by its own.

Inheritance and secondary constructor

If derived class does not contain any primary constructor then it is required to call the base class secondary constructor from derived class using super keyword.For example,

open class Patent {

    constructor(name: String, id: Int) {
        println("execute super constructor $name: $id")
    }
}

class Child : Patent {

    constructor(name: String, id: Int, dept: String) : super(name, id) {
        print("execute child class constructor with property $name, $id, $dept")
    }
}

fun main(args: Array<String>) {
    val child = Child("Ashu", 101, "Developer")
}

Output :

execute super constructor Ashu: 101
execute child class constructor with property Ashu, 101, Developer

In above example, when object of Child class is created, it calls its constructor and initializes its parameters with values “Ashu”, “101” and “Developer”. At the same time Child class constructor calling its supper class constructor using super keyword with values of name and id. Due to the presence of super keyword thebody of superclass constructor executes first and returns to Child class constructor.

Method Overriding

Method overriding means providing the specific implementation of method of super (parent) class into its subclass (child) class.In other words, when subclass redefines or modifies the method of its superclass into subclass, it is known as method overriding. Method overriding is only possible in inheritance.Rules of method overriding :

  1. Parent class and its method or property which is to be overridden must be open (non-final).
  2. Method name of base class and derived class must have same.
  3. Method must have same parameter as in base class.

Example of inheritance without overriding :

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}

class Parrot : Bird() {

}

class Duck : Bird() {

}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

Output :

Bird is flying...
Bird is flying...

In above example, a program without overriding the method of base class we found that both derived classes Parrot and Duck perform the same common operation. To overcome with this problem we use the concept of method overriding.

  • Example of Kotlin method overriding :    

In this example, the method fly() of parent class Bird is overridden in its subclass Parrot and Duck. To override the method of parent class, the parent class and its method which is going to override must be declare as open. At the same time method which is overridden in child class must be prefaced with keyword override.

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override fun fly() {
        println("Parrot is flying...")
    }
}
class Duck: Bird() {
    override fun fly() {
        println("Duck is flying...")
    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

Output :

Parrot is flying...
Duck is flying...
  • Example of property overriding : Property of superclass can also be overridden in its subclass as similar to method. A color property of Bird class is overridden in its subclass Parrot and Duck and modified
open class Bird {
    open var color = "Black"
    open fun fly() {
        println("Bird is flying...")
    }
}

class Parrot : Bird() {
    override var color = "Green"
    override fun fly() {
        println("Parrot is flying...")
    }
}

class Duck : Bird() {
    override var color = "White"
    override fun fly() {
        println("Duck is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)
    val d = Duck()
    d.fly()
    println(d.color)
}

Output :

Parrot is flying...
Green
Duck is flying...
White

We can override the val property with var property in inheritance but vice-versa is not true.

superclass implementation

Derived class can also call its superclass methods and property using super keyword.  For example: 

open class Bird {
    open var color = "Black"
    open fun fly() {
        println("Bird is flying...")
    }
}

class Parrot : Bird() {
    override var color = "Green"
    override fun fly() {
        super.fly()
        println("Parrot is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)
}

Output :

Bird is flying...
Parrot is flying...
Green

multiple class implementation

In Kotlin, derived class uses a supertype name in angle brackets, e.gsuper<Base> when it implements same function name provided in multiple classes.For example, a derived class Parrotextends its superclass Bird and implement Duck interface containing same function fly(). To call particular method of each class and interface we must be mention supertype name in angle brackets as super<Bird>.fly() and super<Duck>.fly() for each method

open class Bird {
    open var color = "Black"
    open fun fly() {
        println("Bird is flying...")
    }
}

interface Duck {
    fun fly() {
        println("Duck is flying...")
    }
}

class Parrot : Bird(), Duck {
    override var color = "Green"
    override fun fly() {
        super<Bird>.fly()
        super<Duck>.fly()
        println("Parrot is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)
}  

Output :

Bird is flying...
Duck is flying...
Parrot is flying...

I hope you found what you were looking for from this tutorial. If you want more Kotlin tutorials like this, then do join our Telegram channel for future updates.

Thanks for reading, have a nice day 🙂

Leave a Comment

Your email address will not be published.