Interfaces and Abstract Classes in Kotlin
In Kotlin, interfaces and abstract classes are essential components of object-oriented programming (OOP). They allow developers to define contracts and provide a base for creating complex systems with well-defined behaviors.
What is an Interface?
An interface in Kotlin is a contract that defines a set of methods that implementing classes must provide. Interfaces can contain abstract methods, default implementations, properties, and even nested types. However, they cannot store state.Defining an Interface
To define an interface, use theinterface
keyword. Here's a simple example:`
kotlin
interface Drivable {
fun drive(): String
}
`
Implementing an Interface
When a class implements an interface, it must provide concrete implementations for all the methods defined in the interface.`
kotlin
class Car : Drivable {
override fun drive(): String {
return "Car is driving"
}
}
class Bike : Drivable {
override fun drive(): String {
return "Bike is riding"
}
}
`
Using Interfaces
You can use interfaces polymorphically, allowing you to treat different implementations in a uniform way:`
kotlin
fun testDrive(vehicle: Drivable) {
println(vehicle.drive())
}
fun main() {
val car = Car()
val bike = Bike()
testDrive(car) // Outputs: Car is driving
testDrive(bike) // Outputs: Bike is riding
}
`
What is an Abstract Class?
An abstract class can be thought of as a class that cannot be instantiated on its own and is intended to be subclassed. It can contain both abstract methods (which must be overridden) and concrete methods (which have an implementation).Defining an Abstract Class
To define an abstract class, use theabstract
keyword. Here's an example:`
kotlin
abstract class Vehicle {
abstract fun drive(): String
fun park() {
println("Vehicle is parked")
}
}
`
Extending an Abstract Class
When a subclass extends an abstract class, it must implement all the abstract methods defined in the superclass:`
kotlin
class Truck : Vehicle() {
override fun drive(): String {
return "Truck is driving"
}
}
class Motorcycle : Vehicle() {
override fun drive(): String {
return "Motorcycle is riding"
}
}
`
Using Abstract Classes
Similar to interfaces, abstract classes can also be used polymorphically:`
kotlin
fun testVehicle(vehicle: Vehicle) {
println(vehicle.drive())
vehicle.park()
}
fun main() {
val truck = Truck()
val motorcycle = Motorcycle()
testVehicle(truck) // Outputs: Truck is driving
// Vehicle is parked
testVehicle(motorcycle) // Outputs: Motorcycle is riding
// Vehicle is parked
}
`
Interfaces vs Abstract Classes
- Instantiation: You cannot create instances of an interface or an abstract class. - Multiple Inheritance: A class can implement multiple interfaces but can only inherit from one abstract class. - State: Abstract classes can have state (properties) while interfaces cannot. - Default Implementations: Interfaces can provide default implementations for methods, while abstract classes can provide concrete methods.Practical Example
Consider a scenario where we have a gaming application where different characters can perform actions:`
kotlin
interface Character {
fun attack(): String
}
abstract class GameCharacter(val name: String) : Character { abstract fun takeDamage(amount: Int): String }
class Warrior(name: String) : GameCharacter(name) { override fun attack(): String { return "$name swings a sword!" }
override fun takeDamage(amount: Int): String { return "$name takes $$amount damage!" } }
class Mage(name: String) : GameCharacter(name) { override fun attack(): String { return "$name casts a fireball!" }
override fun takeDamage(amount: Int): String {
return "$name takes $$amount damage!"
}
}
`
In this example, both Warrior
and Mage
must define how they attack and how they take damage while sharing a common interface and abstract class structure.