Interfaces, Inheritance & Abstract Classes
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
openand 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.