How do I implement interfaces and use multiple inheritance in Kotlin?

In Kotlin, interfaces define a contract that classes can implement. Kotlin supports multiple inheritance of interfaces, but not multiple inheritance of classes.

1. Defining an interface

An interface can declare:

  • abstract properties
  • abstract functions
  • functions with default implementations
interface Drivable {
    val maxSpeed: Int

    fun drive()

    fun stop() {
        println("Stopping the vehicle")
    }
}

Here:

  • maxSpeed must be implemented by any class using the interface.
  • drive() has no body, so it must be implemented.
  • stop() has a default implementation, so overriding it is optional.

2. Implementing an interface

Use : after the class name to implement an interface.

class Car : Drivable {
    override val maxSpeed: Int = 180

    override fun drive() {
        println("The car is driving at up to $maxSpeed km/h")
    }
}

Usage:

fun main() {
    val car = Car()

    car.drive()
    car.stop()
}

Output:

The car is driving at up to 180 km/h
Stopping the vehicle

3. Implementing multiple interfaces

A class can implement more than one interface by separating them with commas.

interface Flyable {
    fun fly() {
        println("Flying")
    }
}

interface Swimmable {
    fun swim() {
        println("Swimming")
    }
}

class Duck : Flyable, Swimmable

Usage:

fun main() {
    val duck = Duck()

    duck.fly()
    duck.swim()
}

4. Handling conflicting default implementations

If two interfaces provide a function with the same signature, the implementing class must override it.

interface Printer {
    fun print() {
        println("Printing from Printer")
    }
}

interface Scanner {
    fun print() {
        println("Printing from Scanner")
    }
}

class AllInOneMachine : Printer, Scanner {
    override fun print() {
        super<Printer>.print()
        super<Scanner>.print()
        println("Printing from AllInOneMachine")
    }
}

Usage:

fun main() {
    val machine = AllInOneMachine()

    machine.print()
}

Output:

Printing from Printer
Printing from Scanner
Printing from AllInOneMachine

The syntax:

super<Printer>.print()

means “call the print() implementation from the Printer interface.”

5. Interfaces with properties

Interfaces can declare properties, but they do not store state directly like classes do.

interface Identifiable {
    val id: String
}

class User(
    override val id: String,
    val name: String
) : Identifiable

Usage:

fun main() {
    val user = User("u123", "Alice")

    println(user.id)
    println(user.name)
}

6. Kotlin and multiple inheritance

Kotlin allows:

class Duck : Flyable, Swimmable

But Kotlin does not allow multiple class inheritance:

open class Animal
open class Machine

// Not allowed in Kotlin
class RobotDog : Animal(), Machine()

Instead, Kotlin allows:

  • one superclass
  • multiple interfaces
open class Animal {
    fun eat() {
        println("Eating")
    }
}

interface Runnable {
    fun run()
}

interface Trainable {
    fun train()
}

class Dog : Animal(), Runnable, Trainable {
    override fun run() {
        println("Dog is running")
    }

    override fun train() {
        println("Dog is training")
    }
}

Key syntax

class ClassName : InterfaceName
class ClassName : InterfaceOne, InterfaceTwo
class ClassName : SuperClass(), InterfaceOne, InterfaceTwo

Summary

  • Use interface to define behavior.
  • Use : to implement interfaces.
  • Use override to implement interface members.
  • Kotlin supports multiple interface inheritance.
  • Kotlin does not support inheriting from multiple classes.
  • If interfaces have conflicting default methods, override the method and choose which parent implementation to call using super<InterfaceName>.

How do I use class inheritance with open and override in Kotlin?

In Kotlin, classes and members are final by default, so you must explicitly mark them as open if you want them to be inherited or overridden.

Basic class inheritance

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

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

Usage:

fun main() {
    val dog = Dog()
    dog.makeSound()
}

Output:

Bark

Key rules

1. Use open on a class to allow inheritance

open class Animal

Without open, this is not allowed:

class Dog : Animal()

because Animal would be final by default.

2. Use open on functions or properties to allow overriding

open fun makeSound() {
    println("Some sound")
}

If a function is not marked open, subclasses cannot override it.

3. Use override in the subclass

override fun makeSound() {
    println("Bark")
}

Kotlin requires override so it is clear that you are replacing behavior from the parent class.

Inheriting from a class with a constructor

If the parent class has a constructor, the subclass must call it:

open class Animal(val name: String) {
    open fun introduce() {
        println("I am $name")
    }
}

class Dog(name: String) : Animal(name) {
    override fun introduce() {
        println("I am a dog named $name")
    }
}

Usage:

fun main() {
    val dog = Dog("Buddy")
    dog.introduce()
}

Output:

I am a dog named Buddy

Overriding properties

Properties can also be open and override:

open class Animal {
    open val sound: String = "Some sound"
}

class Dog : Animal() {
    override val sound: String = "Bark"
}

Usage:

fun main() {
    val dog = Dog()
    println(dog.sound)
}

Output:

Bark

Calling the parent implementation with super

You can call the superclass version using super:

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

class Dog : Animal() {
    override fun makeSound() {
        super.makeSound()
        println("Bark")
    }
}

Output:

Some sound
Bark

Preventing further overriding

An overridden member is open by default. If you want to prevent subclasses from overriding it again, mark it as final:

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

open class Dog : Animal() {
    final override fun makeSound() {
        println("Bark")
    }
}

Now subclasses of Dog cannot override makeSound().

Summary

open class Parent {
    open fun method() {
        println("Parent method")
    }
}

class Child : Parent() {
    override fun method() {
        println("Child method")
    }
}
  • open class means the class can be inherited.
  • open fun or open val means the member can be overridden.
  • override means the subclass is replacing a parent member.
  • Use super.method() to call the parent version.