Inheritance and Interfaces

Inheritance, Interfaces and the open Keyword

Kotlin classes and members are final by default. Mark a class open to allow subclasses, and each replaceable member open too; the subclass must then write override. An interface declares abstract members and may carry default bodies, but no stored state. A class extends one class and any number of interfaces, after one colon.

Priced, Product and EBook: an interface, an open class and a subclassKotlin
interface Priced {
  val price: Double
  fun label(): String = "$%.2f".format(price)   // default method
}
open class Product(val title: String, override val price: Double) : Priced {
  open fun describe() = "$title, ${label()}"
}
class EBook(title: String, price: Double, val sizeMb: Int) : Product(title, price) {
  override fun describe() = super.describe() + " (EPUB, $sizeMb MB)"
  override fun label() = "$%.2f download".format(price)
}
fun main() {
  println(Product("Salt and Saffron", 24.00).describe())
  println(EBook("Patterns of the Deep Web", 39.50, 12).describe())
}
Output
Salt and Saffron, $24.00
Patterns of the Deep Web, $39.50 download (EPUB, 12 MB)

Product(title, price) calls the superclass constructor, and dispatch is virtual: super.describe() calls the EBook override of label(). Without open, class SignedBook(title: String) : Book(title) fails with this type is final, so it cannot be extended.

The BookNest product types: final by default, open where you choose
The BookNest product types: final by default, open where you choose

Use an abstract class when subtypes share state, an interface when they share only a contract, and a sealed type (Sealed and Enum Classes) when the compiler should know every subtype.