Kotlin Inheritance and Polymorphism: open/override, Abstract Classes & Interfaces

1. Inheritance

What is inheritance in Kotlin?

Inheritance allows a class (derived or subclass) to inherit properties and methods from another class (base or superclass), promoting code reuse and hierarchy. Kotlin supports single inheritance for classes (one superclass) but multiple inheritance via interfaces. Use the : operator to specify the superclass.

Syntax:

open class BaseClass { /* properties/methods */ }
class DerivedClass : BaseClass() { /* additional members */ }

Types of Inheritance:

How to Implement: Use the : operator after the class name, calling the superclass constructor. Mark superclasses with open (classes are final by default).

open class Animal(val name: String) {
    fun eat() = println("$name is eating.")
}

class Dog(name: String) : Animal(name) {
    fun bark() = println("$name is barking.")
}

Example:

// Inheritance example
open class Vehicle(val brand: String) {
    open fun start() = println("$brand vehicle starting...")
}

class Car(brand: String) : Vehicle(brand) {
    override fun start() = println("$brand car engine roaring!")
}

class Bike(brand: String) : Vehicle(brand) {
    override fun start() = println("$brand bike humming!")
}

fun main() {
    val car = Car("Toyota")
    val bike = Bike("Honda")
    
    car.start()
    bike.start()
}

Output:

Toyota car engine roaring!
Honda bike humming!

Use in Android/Kotlin Development:

2. Polymorphism

What is polymorphism in Kotlin?

Polymorphism allows objects of different classes to be treated as instances of a common superclass, enabling flexible code. Kotlin supports:

Virtual Methods: Methods in a superclass marked with open, allowing subclasses to override them. The override keyword is required in the subclass.

open class Base {
    open fun method() { /* implementation */ }
}
class Derived : Base() {
    override fun method() { /* new implementation */ }
}

Example:

// Polymorphism example
open class Shape {
    open fun area(): Double = 0.0
    open fun describe() = "A shape"
}

class Circle(val radius: Double) : Shape() {
    override fun area() = Math.PI * radius * radius
    override fun describe() = "Circle with radius $radius"
}

class Rectangle(val width: Double, val height: Double) : Shape() {
    override fun area() = width * height
    override fun describe() = "Rectangle with width $width, height $height"
}

fun printShape(shape: Shape) {
    println("${shape.describe()}: Area = ${shape.area()}")
}

fun main() {
    val shapes = listOf(Circle(5.0), Rectangle(4.0, 6.0))
    for (shape in shapes) {
        printShape(shape)
    }
}

Output:

Circle with radius 5.0: Area = 78.53981633974483
Rectangle with width 4.0, height 6.0: Area = 24.0

Use in Kotlin Development:

3. Abstract Classes and Interfaces

What is an abstract class in Kotlin?

An abstract class cannot be instantiated and is used as a base for subclasses. It may contain abstract methods (no implementation) and concrete methods.

abstract class Base {
    abstract fun abstractMethod()
    fun concreteMethod() = println("Concrete")
}

What is an interface in Kotlin?

An interface defines a contract of methods and properties that implementing classes must provide. Kotlin interfaces can have default implementations.

interface Interface {
    fun method()  // Abstract
    fun defaultMethod() = println("Default")  // Default implementation
}

Example:

// Abstract class and interface example
abstract class Animal {
    abstract fun makeSound()
    fun sleep() = println("Sleeping")
}

interface Flyable {
    fun fly()
    fun land() = println("Landing")  // Default implementation
}

class Bird : Animal(), Flyable {
    override fun makeSound() = println("Chirp!")
    override fun fly() = println("Flying")
}

fun main() {
    val bird = Bird()
    bird.makeSound()
    bird.sleep()
    bird.fly()
    bird.land()
}

Output:

Chirp!
Sleeping
Flying
Landing

Use in Kotlin Development:

4. Common Mistakes and Best Practices

Common Mistakes:

Best Practices: