Table of contents
1.
Introduction
2.
Kotlin Open Class
2.1.
Kotlin Override Keyword
2.2.
Rules of Method Overriding
2.3.
Kotlin Superclass Implementation
3.
Kotlin Inheriting fields from a Class
4.
Kotlin Inheritance and Primary Constructor
5.
Kotlin Inheritance and Secondary Constructor
6.
Kotlin Multiple Class Implementations
7.
FAQs
8.
Key Takeaways
Last Updated: Mar 27, 2024

Kotlin Inheritance

Author Rahul Sain
2 upvotes
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Object-oriented programming languages rely heavily on Inheritance. Inheritance allows you to pass a feature from an existing class (or base or parent class) to a new class (or derived class or child class).

In this article, we will learn about Kotlin Inheritance and the need to use them. But before jumping into this, we would strongly recommend learning about Kotlin Functions.

Now let us study Implementing Inheritance in Kotlin.

Kotlin Open Class

The primary class is the superclass (or parent class), and the class that inherits from the superclass is the subclass (or child class). The subclass incorporates characteristics from the superclass as well as its own.

When two or more classes have identical attributes, the concept of Inheritance is allowed. It enables code reuse. A derived class has a single base class but many interfaces, whereas a base class can have one or more derived classes.

The derived class in Kotlin inherits a base class via the: operator in the class header (after the derived class name or constructor)

Syntax:

open class BaseClass(no: Int){

}
class DerivedClass(no: Int) : BaseClass(no){

}

Assume we have two distinct classes, Circle and Rectangle, each with the specific property and side and their particular function property(). We can inherit the Shape class with similar characteristics thanks to the inheritance feature.

Code:

open class Shape(private val side: Int) {
    protected open fun property(){
        println("this shape has $side sides")
    }
 }
 
 class Circle(private val property: String, private val side: Int): Shape(side) {
    public override fun property(){
        super.property()
        println("this $property has $side sides")
    }
 }
 
 class Rectangle(property: String, side: Int): Shape(side) {
 //    private override fun property(){ // override property incompatible with private
 //        println("this $property has $side sides")
 //    }
 }
 
 fun main() {
    val circle = Circle("circle with radius 10",0)
    circle.property()
 }

Output:

this shape has 0 sides
this circle with radius 10 has 0 sides

We are making a Circle class object in our main(). As we know, CircleCircle is inheriting the properties of the Shape class; hence, we can override the property() of the Shape class in our Circle Class.

super.property() will call the parent property(), which will have side value as same as that of Circle side value. As we have defined that CircleCircle will have two variables while declaring. One is property as a String value, and the second is side as an Integer value. We will be passing this Integer Value to the Shape class and assigning the value to the Shape class side variable.

If we want to use property() of the derived class only then, we don't have to call super.property() to hit up the parent property() method.

For example, the class Any is implicitly inherited by the class Demo.

class Demo

Because Kotlin classes are final by default, they cannot be easily inherited. To inherit a class and make it non-final, we use the open keyword before the class.

open class Demo{ 
// Demo could be extended! 
} 

We are using the override keyword to use the parent class method in its subclass.

Kotlin Override Keyword

In other words, method overriding occurs when a subclass redefines or alters the method of its superclass. Only Inheritance allows for method override.

Rules of Method Overriding

  • The parent class and the method or property overridden must be open (non-final).
  • The method names of the base and derived classes must be the same.
  • The method must have the same parameters as the underlying class.

Kotlin Superclass Implementation

Using the super keyword, a derived class can invoke the methods and properties of its superclass.

Using the super keyword, a derived class can also invoke the methods and properties of its superclass.

The superclass Any is shared by all Kotlin classes. It is the default superclass for a class with no explicitly declared supertypes.

Kotlin Inheriting fields from a Class

We inherit all of its fields and functions when we inherit a class to derive a class. We can use Parent Class attributes and methods in derived classes.

Code:

open class BaseClass{
    val ch = "A"
 }
 class DerivedClass: BaseClass() {
    fun dev() {
        println("ch is equal to $ch")
    }
 }
 fun main() {
    val derivedClass = DerivedClass()
    derivedClass.dev()
 }  

Output:

ch is equal to A

We are calling dev() from the DerivedClass object. One thing to note here is we are using ch variable, which is defined in BaseClass.

We can access ch variable because we have derived the properties and parameters of BaseClass into DerivedClass.

Kotlin Inheritance and Primary Constructor

If the primary function property() is shared by both the base and derived classes, the parameters are initialized in the base class's primary function property(). In the preceding inheritance example, all classes have three parameters: side and property, and all of these parameters are initialized in the base class's primary function property().

When the primary constructors of a base and derived class have different parameters, the base class parameters are initialized from the derived class object.

Code:

open class Shape(property: String, side: Int) {
    init {
        println("Property of Shape is $property.")
        println("Side of Shape is $side")
    }
 }
 
 class Circle(property: String, private val side: Int): Shape(property,side) {
    init {
        println("Property of Circle is $property.")
        println("Side of Circle is $side")
    }
    fun printRadius(){
        println("this circle has $side as a radius")
    }
 }
 
 class Rectangle(property: String,private val side: Int): Shape(property,side) {
    init {
        println("Property of Rectangle is $property.")
        println("Side of Rectangle is $side")
    }
    fun printSides(){
        println("this rectangle has $side sides")
    }
 }
 
 fun main() {
    val circle = Circle("circle with radius 10",10)
    circle.printRadius()
    val rectangle = Rectangle("NaN",5)
    rectangle.printSides()
 }

Output:

Property of Shape is circle with radius 10.
Side of Shape is 10
Property of Circle is circle with radius 10.
Side of Circle is 10
this circle has 10 as a radius
Property of Shape is NaN.
Side of Shape is 5
Property of Rectangle is NaN.
Side of Rectangle is 5
this rectangle has 5 sides

Here, the init block of the parent class is called first before its own init block. The hierarchy of the object goes from top to bottom, first calling the parent class block then the derived class block.

So when we are initializing a child class object first, this class will call its parent class to inherit the parent class parameters and methods.

Kotlin Inheritance and Secondary Constructor

If the derived class lacks the primary constructor, the super keyword must invoke the base class's secondary constructor from the derived class.

Code:

open class Parent {
    constructor(name: String, age: Int) {
        println("execute super constructor $name: $age")
    }
 }
 
 class Child : Parent {
    constructor(name: String, age: Int, dept: String) : super(name, age) {
        print("execute child class constructor with property $name, $age, $dept")
    }
 }
 
 fun main() {
    val child = Child("Coding", 17, "Ninjas")
 }

Output:

execute super constructor Coding: 17
execute child class constructor with property Coding, 17, Ninjas

In the preceding example, when an object of the Child class is created, it invokes its initializer and sets its parameters to "Coding," "17," and "Ninjas." At the same time, the child class construction manager uses the super keyword to invoke the superclass initializer with the values name and id. Because the super keyword is present, the body of the superclass function constructor is executed first and then returns to the Child class function constructor.

Kotlin Multiple Class Implementations

When a derived class implements the same function name of numerous classes, it utilizes a supertype name in angle brackets.

For example, a derived class Orange extends its superclass Fruit and implements the Apple interface, which contains the same function property as the superclass Fruit(). To invoke a certain class or interface method, we must include the supertype name in angle brackets like super<Fruit>. super<Apple> and property() For each method, use property().

Code:

open class Fruit {
    open var color = "Unknown"
    open fun property() {
        println("Fruit color is $color")
    }
 }
 
 interface Apple {
    fun property() {
        println("Apple is a fruit")
    }
 }
 
 class Orange : Fruit(), Apple {
    override var color = "Orange"
    override fun property() {
        super<Fruit>.property()
        super<Apple>.property()
        println("Orange is a fruit")
    }
 }
 
 fun main() {
    val orange = Orange()
    orange.property()
    println(orange.color)
 }

Output:

Fruit color is Orange
Apple is a fruit
Orange is a fruit
Orange

We have now learned about Inheritance and why it should be used. Multiple inheritance support can help us build classes more beautifully.

Note that by Multiple Inheritance we can inherit one class only but can inherit multiple interfaces.

FAQs

  1. Does Kotlin have a static keyword?
    Suppose you are an Android developer who enjoys creating Android applications in Java. In that case, you must have used the static keyword in your code to create static variables, static methods, and so on. Yes, you read that correctly: Kotlin lacks a static keyword.
     
  2. What is lazy in Kotlin?
    Because the same object is accessed throughout, lazy is mostly utilized when accessing a read-only property.
     
  3. What is polymorphism in Kotlin?
    Polymorphism enables computer code to be contextualized. Because it is both intensely and statically typed, Kotlin allows for two types of polymorphism. When the code is compiled, the first type of polymorphism occurs. The other form happens during runtime.

Key Takeaways

Cheers if you reached here!! 

The purpose of this article was to introduce you to the Kotlin Inheritance, the basic syntax of implementing this super, override keyword, and understand the basic core concept about Inheritance in Android Development.

If you want to learn more about Recursion Functions in Kotlin, you can jump to this article which covers them in great detail.

However, learning never stops, and there is more to learn. So head over to our Android Development Course on the Coding Ninjas Website to dive deep into Android Development and build future applications. Till then, Happy Learning!

Live masterclass