Open Classes
In this page:
open class BaseClass(val property: Type) {
open fun method() { }
}
class SubClass(property: Type) : BaseClass(property)
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
open class Animal(val name: String) {
fun describe() = "Animal: $name"
}
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `animal`, set to `Animal("Generic")`
val animal = Animal("Generic")
// Print `animal.describe()` to the console, with a trailing newline
println(animal.describe())
}
Login to try C/C++/Java/PHP code in the editor
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
open class Animal(val name: String)
// Define a class `Dog`
class Dog(name: String) : Animal(name)
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `dog`, set to `Dog("Rex")`
val dog = Dog("Rex")
// Print "Dog name: ${dog.name}" to the console, with a trailing newline
println("Dog name: ${dog.name}")
}
Login to try C/C++/Java/PHP code in the editor
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
open class Animal(val name: String) {
open fun sound(): String = "..."
}
// Define a class `Dog`
class Dog(name: String) : Animal(name) {
override fun sound(): String = "Woof"
}
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `dog`, set to `Dog("Rex")`
val dog = Dog("Rex")
// Print "${dog.name} says ${dog.sound()}" to the console, with a trailing newline
println("${dog.name} says ${dog.sound()}")
}
Login to try C/C++/Java/PHP code in the editor
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
open class Counter {
open var count: Int = 0
protected set
open fun increment() {
count++
}
}
// Define a class `StepCounter`
class StepCounter : Counter() {
override fun increment() {
count += 2
}
}
// Entry point: execution of the program starts here
fun main() {
// Declare a read-only variable `counter`, set to `StepCounter()`
val counter = StepCounter()
counter.increment()
counter.increment()
// Print "Count: ${counter.count}" to the console, with a trailing newline
println("Count: ${counter.count}")
}
Login to try C/C++/Java/PHP code in the editor
- Trying to subclass a regular class and getting a compiler error, forgetting that Kotlin classes are
final(non-inheritable) unless markedopen. - Marking a class
openbut forgetting its individual members also needopenbefore a subclass can override them. - Assuming
openclasses are inherently less safe; being explicit about inheritance is actually a deliberate Kotlin design choice for safety.
- Kotlin classes are
finalby default, meaning they cannot be subclassed unless explicitly markedopen. - Individual members (functions, properties) also need
openbefore 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: