Beginner: Kotlin · Classes, objects and collections · topic 11 of 50 · 25 min
Inheritance and interfaces
Explanation
Why inheritance?
Sometimes several kinds of things share a lot: a bus ticket, a train ticket and a flight ticket all have a passenger name and a price, but each calculates its fee differently. Inheritance lets a subclass (child) reuse the properties and functions of a superclass (parent) and change only what differs.
open and override
Kotlin chose a safe default: classes and their functions are final, meaning they cannot be inherited or overridden, unless you say open. This prevents accidental changes in subclasses that the original author never planned for.
open class Ticket(val passenger: String, val baseFare: Int) {
open fun total(): Int = baseFare
fun summary() = "$passenger: Rs ${total()}"
}
class TrainTicket(passenger: String, baseFare: Int, val tatkal: Boolean) : Ticket(passenger, baseFare) {
override fun total(): Int = if (tatkal) baseFare + 300 else baseFare
}
class FlightTicket(passenger: String, baseFare: Int) : Ticket(passenger, baseFare) {
override fun total(): Int = baseFare + 750 // fees
}
fun main() {
val tickets: List<Ticket> = listOf(TrainTicket("Ravi", 1200, true), FlightTicket("Meena", 4500))
for (t in tickets) println(t.summary())
}Polymorphism (many forms) means one call, t.total(), does different things depending on the actual object. The loop does not need to know which kind of ticket it has.
The subclass header TrainTicket(...) : Ticket(passenger, baseFare) passes values up to the parent constructor. The parent's properties (passenger, baseFare) are then available in the child without being declared again.
super
class FestiveTrainTicket(p: String, fare: Int) : Ticket(p, fare) {
override fun total(): Int = super.total() - 100 // reuse the parent's logic, then adjust
}Abstract classes
An abstract class cannot be created directly; it exists to be inherited. It can declare abstract members with no body, which every subclass must implement, alongside normal shared code.
abstract class Shape {
abstract fun area(): Double
fun describe() = "Area: %.2f".format(area())
}
class Circle(val r: Double) : Shape() {
override fun area() = Math.PI * r * r
}Interfaces
An interface describes an ability, like "can be shared" or "can be paid". Many unrelated classes can implement it, and a class can implement several interfaces but extend only one class. Interface functions can have default bodies.
interface Payable {
fun amountPaise(): Long
fun display() = "Rs ${amountPaise() / 100}" // default implementation
}
interface Shareable {
fun shareText(): String
}
class Invoice(val no: String, val paise: Long) : Payable, Shareable {
override fun amountPaise() = paise
override fun shareText() = "Invoice $no: ${display()}"
}Composition over inheritance
Deep inheritance trees (A extends B extends C extends D) become hard to change. Most modern Kotlin and Android code prefers composition: a class holds other objects that do parts of the work, and interfaces describe what can be swapped. Use inheritance for a genuine "is a" relationship and keep trees shallow.
Common mistakes
- Forgetting open: "This type is final, so it cannot be inherited from".
- Forgetting override when redefining a function: the compiler requires it explicitly.
- Trying to inherit from two classes. Use one class plus interfaces.
- Building deep hierarchies for code reuse. Prefer small classes composed together.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Inheritance and interfaces · 1/6
Inheritance lets a subclass reuse and change a parent class.
Prefer a video by a teacher? Find free videos on “kotlin inheritance open override abstract interface” on YouTube ↗
In real life: Notification channels
A banking app sends alerts by SMS, email and push notification. A Notifier interface with send(message) is implemented by SmsNotifier, EmailNotifier and PushNotifier. The alert code holds a List<Notifier> and calls send on each. Adding WhatsApp means one new class implementing Notifier, with no change to the alert code.
interface Notifier { fun send(msg: String): String }
class SmsNotifier(val phone: String) : Notifier {
override fun send(msg: String) = "SMS to $phone: $msg"
}
class EmailNotifier(val email: String) : Notifier {
override fun send(msg: String) = "Email to $email: $msg"
}
fun main() {
val channels: List<Notifier> = listOf(SmsNotifier("98xxxx10"), EmailNotifier("a@b.in"))
channels.forEach { println(it.send("Rs 2,000 debited")) }
}Practice (0/3 done)
Why does this not compile? class Animal class Dog : Animal()
What does this print? open class A { open fun hi() = "A" } class B : A() { override fun hi() = "B" + super.hi() } fun main() { val x: A = B(); println(x.hi()) }
Create an interface Discountable with fun discountPercent(): Int and a default fun priceAfter(price: Int) = price - price * discountPercent() / 100. Implement it in StudentCustomer (10%) and SeniorCustomer (15%), put both in a List<Discountable>, and print the price after discount for Rs 1,000.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Collections: List, Set and MapClasses, objects and collections · same module
- Inheritance, interfaces, mixins and extensionsFlutter and Dart · Null safety and object-oriented Dart
- Inheritance with extendsJava Programming (Core to Spring Boot) · Inheritance, polymorphism and interfaces
- Inheritance and compositionJavaScript Programming (language in depth) · Scope, this, prototypes and classes
- Inheritance and compositionPython Programming · Object-oriented programming
- Abstract classes, interfaces and good class designC++ Programming (modern C++ and DSA) · Operator overloading, inheritance and polymorphism
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which keyword allows a class to be inherited?
Answer: open
Classes are final unless marked open (or abstract).
How many classes can a Kotlin class extend?
Answer: One
One superclass, but many interfaces.
What is polymorphism?
Answer: One call behaving differently depending on the actual object
The overridden function of the real object runs.
Can an interface function have a default body in Kotlin?
Answer: Yes
Interfaces can provide default implementations.
How many classes can a Dart class extend?Related
Answer: One
Single inheritance; many interfaces and mixins.
How many classes can a Java class directly extend?Related
class B extends A {} (no constructor). What does new B(1, 2) do?Related
Answer: Calls A's constructor with 1, 2
A missing constructor in a subclass passes all arguments to super automatically.
A child class defines speak() and so does its parent. Which runs for child.speak()?Related
Answer: The child's version
Python looks for the method on the child first. This is overriding.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Classes, objects and collections” before its exam: Collections: List, Set and Map, Collection operations.
- Module 3 exam: Classes, objects and collections · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Coroutines and Flow. 50 topics left in the course before the final exam.