Kotlin makes object-oriented programming simple and powerful with its inheritance system. If you’re coming from Java or another OOP language, understanding Kotlin inheritance will help you write smarter, reusable code with fewer lines and more efficiency.
In this guide, we’ll break down Kotlin inheritance step by step, making it easy to grasp and apply in real-world scenarios.
What Is Kotlin Inheritance?
Inheritance is a fundamental concept in object-oriented programming (OOP). It allows a class to acquire the properties and behaviors of another class, reducing code duplication and improving maintainability.
In Kotlin, inheritance works by creating a base class (parent class) and allowing other classes (child classes) to derive from it.
By default, all Kotlin classes are final (cannot be inherited). To make a class inheritable, you must explicitly use the open
keyword.
// Parent class
open class Animal {
fun eat() {
println("This animal is eating")
}
}
// Child class inheriting from Animal
class Dog : Animal() {
fun bark() {
println("The dog is barking")
}
}
fun main() {
val myDog = Dog()
myDog.eat() // Inherited method
myDog.bark() // Child class method
}
Here,
- The
Animal
class is open, making it inheritable. - The
Dog
class extendsAnimal
using the:
symbol. - The
Dog
class gets access to theeat()
function fromAnimal
. - The
bark()
function is specific toDog
.
Primary Constructor in Kotlin Inheritance
When a child class inherits from a parent class that has a constructor, it must initialize it. Here’s how it works:
open class Animal(val name: String) {
fun eat() {
println("$name is eating")
}
}
class Dog(name: String) : Animal(name) {
fun bark() {
println("$name is barking")
}
}
fun main() {
val myDog = Dog("Buddy")
myDog.eat()
myDog.bark()
}
What’s Happening Here?
- The
Animal
class has a primary constructor with aname
parameter. - The
Dog
class calls theAnimal
constructor using: Animal(name)
. - When we create a
Dog
object, we pass a name that is used in botheat()
andbark()
.
Overriding Methods in Kotlin
Kotlin allows child classes to modify or override methods from the parent class using the override
keyword.
open class Animal {
open fun makeSound() {
println("Animal makes a sound")
}
}
class Dog : Animal() {
override fun makeSound() {
println("Dog barks")
}
}
fun main() {
val myDog = Dog()
myDog.makeSound()
}
Here,
- The
makeSound()
function inAnimal
is open, allowing it to be overridden. Dog
provides its own implementation usingoverride
.- Now, when
makeSound()
is called onDog
, it prints “Dog barks” instead of “Animal makes a sound”.
If we remove open
from the method but keep the class open
, will it affect our code? Yes, we will get the following compile-time error:
'makeSound' in 'Animal' is final and cannot be overridden.
Using Superclass Methods
Sometimes, you want to modify a method but still call the original method from the parent class. You can do this using super
.
open class Animal {
open fun makeSound() {
println("Animal makes a sound")
}
}
class Dog : Animal() {
override fun makeSound() {
super.makeSound()
println("Dog barks")
}
}
fun main() {
val myDog = Dog()
myDog.makeSound()
}
Here, super.makeSound()
calls the parent class method before executing the child class implementation.
Abstract Classes in Kotlin Inheritance
An abstract class cannot be instantiated and may contain abstract methods that must be implemented by child classes.
abstract class Animal {
abstract fun makeSound()
}
class Dog : Animal() {
override fun makeSound() {
println("Dog barks")
}
}
fun main() {
val myDog = Dog()
myDog.makeSound()
}
Why Use Abstract Classes?
- They define a template for subclasses.
- They ensure that all child classes implement necessary methods.
Interfaces vs. Inheritance in Kotlin
Kotlin also supports interfaces, which are similar to abstract classes but allow multiple implementations.
interface Animal {
fun makeSound()
}
class Dog : Animal {
override fun makeSound() {
println("Dog barks")
}
}
fun main() {
val myDog = Dog()
myDog.makeSound()
}
Key Differences:
- A class can inherit only one superclass but implement multiple interfaces.
- Interfaces cannot store state (i.e., no instance variables), while abstract classes can.
Conclusion
Kotlin inheritance is a powerful feature that helps you write smarter, reusable code. By using open classes, overriding methods, abstract classes, and interfaces, you can structure your code efficiently.
Here’s a quick recap:
- Use
open
to make a class inheritable. - Override methods with
override
. - Use
super
to call the parent method. - Use
abstract
for mandatory implementations.
By mastering Kotlin inheritance, you can build scalable, maintainable, and clean applications.