Inheritance lets you build new classes on top of existing ones. In Kotlin, classes are closed by default — you have to explicitly opt in with the open keyword. It's a design choice that makes code safer and easier to reason about.
The open keyword
By default, every class in Kotlin is final — it can't be inherited. To allow inheritance, mark the class with open.
open class Animal(val name: String)
class Dog(name: String) : Animal(name) {
fun bark() = println("$name says woof!")
}
fun main() {
val dog = Dog("Buddy")
dog.bark()
}
Use a colon : followed by the supertype. If the superclass has a constructor, you pass arguments right there.
Overriding methods
Methods also need the open keyword to be overridable. Use override in the subclass.
open class Animal {
open fun sound() = println("Some sound")
}
class Cat : Animal() {
override fun sound() = println("Meow!")
}
fun main() {
val cat = Cat()
cat.sound()
}
If you don't mark the method as open in the parent, subclasses can't override it. Keeps your API predictable.
Abstract classes
Abstract classes are open by nature — they define a contract that subclasses must fulfill.
abstract class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
class Square(val side: Double) : Shape() {
override fun area() = side * side
}
fun main() {
val shapes = listOf(Circle(5.0), Square(4.0))
shapes.forEach { println(it.area()) }
}
Abstract methods have no body. Every concrete subclass must provide an implementation. It's a promise, not an option.
Try it Yourself →