← Back to Kotlin Course | Chapter 7: Inheritance & Interfaces | Lesson 1 of 7

Open Classes

An open class is one that has given permission to be extended into new, more specific classes; regular classes refuse this by default.

Classes Are Final by Default

Unlike Java, a Kotlin class cannot be subclassed unless it is explicitly marked open. This deliberate default prevents accidental fragile inheritance hierarchies.

Example: Classes Are Final by Default

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

fun main() {
    val animal = Animal("Generic")
    println(animal.describe())
}

Subclassing an Open Class

A class marked open can be extended with class Sub : Base(constructorArgs), which calls the base class's constructor as part of creating the subclass instance.

Example: Subclassing an Open Class

markup
open class Animal(val name: String)

class Dog(name: String) : Animal(name)

fun main() {
    val dog = Dog("Rex")
    println("Dog name: ${dog.name}")
}

Open Members

Marking a class open only allows subclassing; each individual function or property that should be overridable must also be marked open separately.

Example: Open Members

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

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

fun main() {
    val dog = Dog("Rex")
    println("${dog.name} says ${dog.sound()}")
}

Why Closed by Default Helps

Requiring open explicitly forces the class author to think about which parts of a class are safe to extend, avoiding accidental behavior changes in subclasses that a truly closed design would prevent entirely.

Example: Why Closed by Default Helps

markup
open class Counter {
    open var count: Int = 0
        protected set

    open fun increment() {
        count++
    }
}

class StepCounter : Counter() {
    override fun increment() {
        count += 2
    }
}

fun main() {
    val counter = StepCounter()
    counter.increment()
    counter.increment()
    println("Count: ${counter.count}")
}
Common Mistakes
  1. Trying to subclass a regular class and getting a compiler error, forgetting that Kotlin classes are final (non-inheritable) unless marked open.
  2. Marking a class open but forgetting its individual members also need open before a subclass can override them.
  3. Assuming open classes are inherently less safe; being explicit about inheritance is actually a deliberate Kotlin design choice for safety.
Chapter Summary
  • Kotlin classes are final by default, meaning they cannot be subclassed unless explicitly marked open.
  • Individual members (functions, properties) also need open before a subclass can override them.
  • This 'closed by default' design avoids fragile base class problems common in languages where everything is inheritable by default.
  • A subclass is declared with class Sub : Base(...), calling the base class's constructor.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.