Sobes.tech
Junior

How is inheritance and polymorphism organized in Kotlin?

sobes.tech AI

Answer from AI

In Kotlin, inheritance is implemented through classes and interfaces. Classes can inherit from only one other class (single inheritance), but can implement multiple interfaces.

By default, all classes in Kotlin are 'final', meaning they cannot be inherited. To allow inheritance, a class must be explicitly marked with the open keyword.

Class inheritance:

open class Shape { // Base class, marked as open
    open fun draw() { // Method that can be overridden
        println("Drawing a shape")
    }
}

class Circle : Shape() { // Inheriting from Shape
    override fun draw() { // Overriding the method
        println("Drawing a circle")
    }
}

In the constructor of the derived class, it is necessary to call the constructor of the base class, explicitly or implicitly.

Interfaces:

Interfaces in Kotlin are similar to interfaces in Java 8 and can contain abstract methods and methods with implementations. Classes can implement one or more interfaces.

interface Drawable {
    fun draw() // Abstract method
    fun description() { // Method with default implementation
        println("This is a drawable object")
    }
}

class Square : Drawable {
    override fun draw() { // Implementation of abstract method
        println("Drawing a square")
    }
    // description() can be overridden, but it is not mandatory
}

Polymorphism:

Polymorphism in Kotlin is achieved by working with objects of different classes through a common base type (class or interface). This allows calling methods specific to the actual object type at runtime.

fun render(drawable: Drawable) {
    drawable.draw() // Calls the draw() method depending on the actual object type
    drawable.description()
}

fun main() {
    val circle: Shape = Circle() // Circle object is considered as Shape
    circle.draw() // Calls draw() from Circle due to polymorphism

    val square: Drawable = Square() // Square object is considered as Drawable
    render(square) // Calls draw() and description() from Square
}

In this example, render works with any object implementing Drawable. The call to drawable.draw() will execute the draw method implementation for the specific object type (Square in this case).

Difference between class inheritance and interface implementation:

  • Class inheritance: Establishes an "is-a" relationship. The derived class inherits the state and behavior of the base class.
  • Interface implementation: Defines a "capability" or "contract". The class promises to provide implementations for all abstract methods of the interface.

Comparison table:

Feature Class inheritance Interface implementation
Relationship type is-a Capability / Contract
Multiple inheritance Single Multiple
State Inherits state from base class Does not inherit state
Method implementation Can contain implementation Can contain default implementation (from Java 8)