Kotlin Inheritance
Inheritance lets a class reuse and extend the properties and functions of another class.
Opening a Class for Inheritance
By default, every Kotlin class is final, meaning no other class can inherit from it. To allow inheritance, mark the class (and any function you want to be overridable) with the open keyword. This is a deliberate design choice in Kotlin: inheritance must be opted into explicitly.
An Open Base Class
open class Animal(val name: String) {
open fun makeSound(): String {
return "..."
}
}
class Dog(name: String) : Animal(name) {
override fun makeSound(): String {
return "Woof!"
}
}
fun main() {
val dog = Dog("Rex")
println("${dog.name} says ${dog.makeSound()}")
}The Colon and Override Keywords
A subclass declares its parent using a colon followed by the parent class name and its constructor call, like : Animal(name). To replace a parent's open function with new behavior, the subclass uses the override keyword - both open and override are required, so accidental overriding never happens by mistake.
- open marks a class or member as inheritable/overridable
- : SuperClass(args) establishes the parent-child relationship
- override replaces a parent's open function or property in the subclass
- super.functionName() calls the parent's original implementation from within an override
Calling the Parent With super
open class Vehicle(val brand: String) {
open fun describe(): String = "A vehicle made by $brand"
}
class Motorcycle(brand: String, val cc: Int) : Vehicle(brand) {
override fun describe(): String {
return super.describe() + " with a $cc cc engine"
}
}
fun main() {
val moto = Motorcycle("Vantis", 650)
println(moto.describe())
}Polymorphism Through Inheritance
Because a subclass 'is a' kind of its superclass, you can store subclass objects in a variable typed as the superclass. When you call an overridden function on that variable, Kotlin runs the subclass's version at runtime - this is polymorphism, and it's one of the most powerful benefits of inheritance.
Polymorphic Behavior
open class Shape {
open fun area(): Double = 0.0
}
class Circle(val radius: Double) : Shape() {
override fun area(): Double = Math.PI * radius * radius
}
class Square(val side: Double) : Shape() {
override fun area(): Double = side * side
}
fun main() {
val shapes: List<Shape> = listOf(Circle(2.0), Square(3.0))
for (shape in shapes) {
println("Area: ${shape.area()}")
}
}With inheritance, you've now covered the four essential OOP building blocks in Kotlin: classes and objects, constructors, class functions, and inheritance with polymorphism.
Exercise: Kotlin Inheritance
Can any Kotlin class be subclassed by default, without changing anything about it?