Kotlin makes object-oriented programming easier with features like abstract classes and interfaces. But when should you use abstract classes in Kotlin, and when should you avoid them? Let’s break it down in simple terms.
What Are Abstract Classes in Kotlin?
An abstract class in Kotlin is a class that cannot be instantiated directly. It acts as a blueprint for other classes, providing a structure but leaving implementation details to subclasses. Means, It is designed to serve as a base for other classes. Abstract classes may contain both abstract (unimplemented) methods and concrete (implemented) methods.
Key Features of Abstract Classes:
- Cannot be instantiated directly
- Can have abstract methods (methods without implementation)
- Can have implemented methods
- Can hold state with properties
- Supports constructors
abstract class Animal(val name: String) {
abstract fun makeSound()
}
class Dog(name: String) : Animal(name) {
override fun makeSound() {
println("Woof! Woof!")
}
}
fun main() {
val myDog = Dog("Buddy")
myDog.makeSound() // Outputs: Woof! Woof!
}
Here,
Animal
is an abstract class that defines an abstract methodmakeSound()
.Dog
is a concrete subclass that implementsmakeSound()
.- We cannot create an instance of
Animal
directly, only its subclass (Dog
).
When to Use Abstract Classes in Kotlin
1. When You Need to Share Common State
If multiple subclasses share common properties or behavior, an abstract class helps avoid code duplication.
abstract class Vehicle(val speed: Int) {
fun showSpeed() {
println("Speed: $speed km/h")
}
}
class Car(speed: Int) : Vehicle(speed)
class Bike(speed: Int) : Vehicle(speed)
Both Car
and Bike
inherit the speed
property and showSpeed()
method from Vehicle
.
2. When You Want to Provide Partial Implementation
Sometimes, an abstract class provides some default behavior while requiring subclasses to define specific methods.
abstract class Appliance {
fun plugIn() {
println("Appliance plugged in")
}
abstract fun operate()
}
class WashingMachine : Appliance() {
override fun operate() {
println("Washing clothes")
}
}
Here, Appliance
has a plugIn()
method that is common to all appliances, but operate()
must be defined by each specific appliance.
3. When You Need a Base Class with Constructors
Unlike interfaces, abstract classes can have constructors to initialize properties.
abstract class Employee(val name: String, val id: Int) {
abstract fun work()
}
class Developer(name: String, id: Int) : Employee(name, id) {
override fun work() {
println("Writing code")
}
}
Here, Employee
initializes name
and id
, saving boilerplate code in subclasses.
When NOT to Use Abstract Classes in Kotlin
1. When You Only Need Functionality, Not State
If you only need to define behavior (methods) without storing data, use interfaces instead.
interface Flyable {
fun fly()
}
class Bird : Flyable {
override fun fly() {
println("Bird is flying")
}
}
Interfaces allow multiple inheritance, whereas abstract classes do not.
2. When You Need Multiple Inheritance
Kotlin does not support multiple class inheritance, but a class can implement multiple interfaces.
interface Drivable {
fun drive()
}
interface Floatable {
fun float()
}
class AmphibiousCar : Drivable, Floatable {
override fun drive() {
println("Driving on road")
}
override fun float() {
println("Floating on water")
}
}
If we used an abstract class instead of an interface, we couldn’t achieve this flexibility.
3. When You Want Simplicity
Abstract classes add structure, but sometimes, simple data classes or regular classes work just fine.
data class Product(val name: String, val price: Double)
If all you need is a simple data container, an abstract class is unnecessary.
Conclusion
Use abstract classes in Kotlin when you need a base class that shares state or provides partial implementation. If you only need to define behavior, interfaces are a better choice.
When designing your Kotlin applications, ask yourself:
- Do I need to share logic? → Use an abstract class.
- Do I just need a contract without implementation? → Use an interface.
- Do I need multiple inheritance? → Use interfaces.
Choosing the right approach makes your code cleaner, more maintainable, and flexible.