← All courses

Interfaces, Inheritance & Abstract Classes

🗓 May 31, 2026 ⏱ 2 min read

Inheritance

Inheritance lets one class reuse and extend another. In Kotlin, classes are final by default — you must mark a class open before it can be inherited, and mark methods open before they can be overridden. This prevents accidental, fragile hierarchies.

open class Animal(val name: String) {
    open fun sound(): String = "..."
    fun describe() = "$name says ${sound()}"
}

class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}

class Cat(name: String) : Animal(name) {
    override fun sound() = "Meow"
}

println(Dog("Rex").describe())   // Rex says Woof

Abstract classes

An abstract class cannot be created directly; it defines a partial template that subclasses must complete.

abstract class Shape {
    abstract fun area(): Double          // must be implemented
    fun describe() = "Area is ${area()}" // shared logic
}

class Circle(val r: Double) : Shape() {
    override fun area() = Math.PI * r * r
}

Interfaces

An interface is a contract: a list of functions a class promises to provide. A class can implement many interfaces (but inherit only one class), which makes interfaces the main tool for flexible design.

interface Clickable {
    fun onClick()
    fun onLongClick() = println("default long click")  // can have a default
}

interface Focusable {
    fun onFocus()
}

class Button : Clickable, Focusable {
    override fun onClick() = println("clicked")
    override fun onFocus() = println("focused")
}

Interface vs abstract class

  • Use an interface to describe a capability that many unrelated classes can have (Clickable, Comparable). A class can implement several.
  • Use an abstract class when classes share a common base and some real implementation/state.

Polymorphism in action

val animals: List<Animal> = listOf(Dog("Rex"), Cat("Tom"))
animals.forEach { println(it.sound()) }   // Woof, Meow

Common mistakes

  • Forgetting open and wondering why you can’t inherit/override.
  • Building deep inheritance trees — prefer interfaces and composition.
  • Putting state in an interface — interfaces can’t hold backing fields.
Summary: Classes are final unless open. Use interfaces for capabilities (many per class), abstract classes for a shared base with state. Favour composition over deep inheritance.