Kotlin – 17 – Abstract Classes in Kotlin

Abstract classes are a crucial component of object-oriented programming (OOP) in Kotlin. They provide a way to define classes with shared characteristics and behaviors while enforcing that certain methods be implemented by their subclasses. In this guide, we’ll delve into abstract classes in Kotlin, how to define them, their key features, and when to use them.

Defining an Abstract Class

An abstract class in Kotlin is declared using the abstract keyword. It serves as a blueprint for other classes and can contain both abstract and concrete (implemented) members, such as methods and properties. Here’s the basic syntax of an abstract class:

abstract class MyAbstractClass {
    // Abstract properties (no initial value)
    abstract val abstractProperty: Int

    // Abstract methods (no implementation)
    abstract fun abstractMethod()

    // Concrete method with implementation
    fun concreteMethod() {
        println("This is a concrete method.")
    }
}

In this example, MyAbstractClass is an abstract class that includes an abstract property abstractProperty, an abstract method abstractMethod(), and a concrete method concreteMethod().

Abstract Properties

Abstract properties in an abstract class are declared without an initial value. They must be overridden by concrete subclasses that provide a value. For example:

abstract class Shape {
    abstract val area: Double
}

In this case, any concrete subclass of Shape must provide an implementation for the area property.

Abstract Methods

Abstract methods in an abstract class are declared without an implementation. Subclasses are required to override these methods with their own implementations. Here’s an example:

abstract class Shape {
    abstract fun area(): Double
}

In this example, any subclass of Shape must provide a concrete implementation for the area() method.

Concrete Methods

Abstract classes can also include concrete methods with implementations. Subclasses inherit these concrete methods and can choose to override them or use them as-is. For example:

abstract class Vehicle {
    fun start() {
        println("Vehicle started.")
    }

    abstract fun stop()
}

In this example, the start() method is a concrete method with an implementation provided in the abstract class, while the stop() method is declared as abstract, requiring concrete subclasses to implement it.

Creating Subclasses

To create a concrete class that extends an abstract class, you use the : symbol followed by the name of the abstract class in the class header. The subclass must provide implementations for all abstract properties and methods. Here’s an example:

class Circle(val radius: Double) : Shape() {
    override val area: Double
        get() = Math.PI * radius * radius
}

In this example, Circle is a concrete subclass of the Shape abstract class. It provides an implementation for the area property using a backing field.

Use Cases for Abstract Classes

Abstract classes are useful in scenarios where you want to define a common structure for a group of related classes but don’t want to create instances of the abstract class itself. Here are some common use cases for abstract classes:

  1. Creating Frameworks: Abstract classes can be used to create frameworks or libraries where the abstract class defines the core functionality, and concrete subclasses provide customized implementations.
  2. Defining Common Interfaces: Abstract classes can define a common set of methods or properties that multiple classes must implement, ensuring consistency in the interface.
  3. Code Reusability: Abstract classes allow you to reuse code by providing a base implementation that subclasses inherit.
  4. Enforcing Contracts: Abstract classes can enforce that certain methods or properties must be implemented by subclasses, ensuring that specific functionality is present in all derived classes.
  5. Hierarchy: Abstract classes can establish a hierarchy of classes, with each level providing additional or specialized functionality.
Command and Example

Here’s a complete example demonstrating the use of abstract classes in Kotlin:

abstract class Shape {
    abstract fun area(): Double
}

class Circle(val radius: Double) : Shape() {
    override fun area(): Double {
        return Math.PI * radius * radius
    }
}

class Rectangle(val width: Double, val height: Double) : Shape() {
    override fun area(): Double {
        return width * height
    }
}

fun main() {
    val circle = Circle(5.0)
    val rectangle = Rectangle(4.0, 6.0)

    println("Circle Area: ${circle.area()}")
    println("Rectangle Area: ${rectangle.area()}")
}

In this example, we have an abstract class Shape with an abstract method area(). Two concrete subclasses, Circle and Rectangle, implement the area() method with their own implementations. The main() function demonstrates creating objects of both subclasses and calculating and printing their respective areas, showcasing how abstract classes can provide a common structure for related classes while enforcing certain behavior.