Kotlin Polymorphism

Introduction

Polymorphism is a core concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common superclass. It enables a single interface to be used for a general class of actions, allowing for code that is more flexible and reusable. Polymorphism can be achieved through inheritance, interfaces, and overriding methods.

Types of Polymorphism

  1. Compile-time polymorphism (Static polymorphism): Achieved through method overloading.
  2. Run-time polymorphism (Dynamic polymorphism): Achieved through method overriding.

Compile-time Polymorphism (Method Overloading)

Method overloading is a feature that allows a class to have more than one method with the same name, but with different parameters.

Example

fun main() {
    val calculator = Calculator()
    println(calculator.add(5, 3))          // Calls add(int, int)
    println(calculator.add(5.0, 3.0))      // Calls add(double, double)
    println(calculator.add(5, 3, 2))       // Calls add(int, int, int)
}

class Calculator {
    // Overloaded methods
    fun add(a: Int, b: Int): Int {
        return a + b
    }

    fun add(a: Double, b: Double): Double {
        return a + b
    }

    fun add(a: Int, b: Int, c: Int): Int {
        return a + b + c
    }
}

Output:

8
8.0
10

Run-time Polymorphism (Method Overriding)

Method overriding occurs when a subclass provides a specific implementation for a method that is already defined in its superclass.

Example

fun main() {
    val animal: Animal = Dog()
    animal.makeSound()  // Calls the overridden method in Dog

    val cat: Animal = Cat()
    cat.makeSound()     // Calls the overridden method in Cat
}

open class Animal {
    open fun makeSound() {
        println("Animal makes a sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("Dog barks")
    }
}

class Cat : Animal() {
    override fun makeSound() {
        println("Cat meows")
    }
}

Output:

Dog barks
Cat meows

Polymorphism with Interfaces

Polymorphism can also be achieved using interfaces. A class can implement multiple interfaces, and the same interface can be used by different classes.

Example

fun main() {
    val dog: Animal = Dog()
    dog.makeSound()

    val bird: Animal = Bird()
    bird.makeSound()
}

interface Animal {
    fun makeSound()
}

class Dog : Animal {
    override fun makeSound() {
        println("Dog barks")
    }
}

class Bird : Animal {
    override fun makeSound() {
        println("Bird chirps")
    }
}

Output:

Dog barks
Bird chirps

Example Program with Polymorphism

Here is an example program that demonstrates various aspects of polymorphism in Kotlin:

fun main() {
    // Using method overloading
    val calculator = Calculator()
    println(calculator.add(5, 3))          // Calls add(int, int)
    println(calculator.add(5.0, 3.0))      // Calls add(double, double)
    println(calculator.add(5, 3, 2))       // Calls add(int, int, int)

    // Using method overriding
    val animal: Animal = Dog()
    animal.makeSound()  // Calls the overridden method in Dog

    val cat: Animal = Cat()
    cat.makeSound()     // Calls the overridden method in Cat

    // Using interfaces for polymorphism
    val dog: AnimalInterface = DogInterface()
    dog.makeSound()

    val bird: AnimalInterface = BirdInterface()
    bird.makeSound()
}

// Method overloading
class Calculator {
    fun add(a: Int, b: Int): Int {
        return a + b
    }

    fun add(a: Double, b: Double): Double {
        return a + b
    }

    fun add(a: Int, b: Int, c: Int): Int {
        return a + b + c
    }
}

// Method overriding
open class Animal {
    open fun makeSound() {
        println("Animal makes a sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("Dog barks")
    }
}

class Cat : Animal() {
    override fun makeSound() {
        println("Cat meows")
    }
}

// Interface for polymorphism
interface AnimalInterface {
    fun makeSound()
}

class DogInterface : AnimalInterface {
    override fun makeSound() {
        println("Dog barks")
    }
}

class BirdInterface : AnimalInterface {
    override fun makeSound() {
        println("Bird chirps")
    }
}

Output:

8
8.0
10
Dog barks
Cat meows
Dog barks
Bird chirps

Conclusion

In this chapter, you learned about polymorphism in Kotlin, including how to achieve compile-time polymorphism using method overloading and run-time polymorphism using method overriding. You also learned how to use interfaces for polymorphism. Polymorphism allows for more flexible and reusable code by enabling a single interface to represent different types of actions. Understanding and applying polymorphism is crucial for writing robust and maintainable Kotlin programs.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top