Abstract Class in Kotlin

Learn via video courses
Topics Covered

Overview

An abstract class in Kotlin is a fundamental feature that empowers developers to create efficient and organized code structures. In this article, we delve into abstract class in Kotlin and its significance in object-oriented programming. You will learn how to define an abstract class in Kotlin and leverage its abstract properties and methods. We will discover how abstract classes in Kotlin serve as blueprints for subclassed classes, enforcing a contract for shared behaviors, and promoting code reusability.

Declaration of Abstract Class with Abstract Methods

An abstract class in Kotlin is a class that cannot be instantiated on its own and is designed to serve as a blueprint or template for other classes. It may contain both abstract (unimplemented) and concrete (implemented) properties and methods. Abstract classes are typically used to define a common structure or interface for a group of related classes. One important feature of an abstract class is that it can have abstract methods, which are methods declared without an implementation in the abstract class itself. Subclasses of the abstract class are required to provide concrete implementations for these abstract methods.

Here's an example of an abstract class in Kotlin with an abstract method:

Code:

Explanation:

In this example:

We declare an abstract class called Animal using the abstract keyword. The abstract class contains a concrete property category with a default value.

It also includes two abstract methods, makeSound() and eat(food: String), declared without implementations.

Subclasses that inherit from this Animal abstract class will be required to provide concrete implementations for the makeSound() and eat(food: String) methods.

Here is an example of a subclass that implements the Animal abstract class in Kotlin:

Code:

Output:

Example of Abstract and Non-abstract Members in an Abstract Class

Let us create an abstract class in Kotlin that contains both abstract and non-abstract (concrete) members.

Code:

Explanation:

In this example, the abstract class Vehicle contains both abstract and concrete members:

  • brand is an abstract property. Subclasses must provide an implementation for this property.
  • year is a concrete property with a default value.
  • startEngine() is an abstract method without an implementation. Subclasses must provide an implementation.
  • stopEngine() is a concrete method with an implementation in the abstract class.

Now, let's create a subclass of Vehicle and provide implementations for the abstract members:

Explanation:

In the Car class:

  • We provide a concrete implementation for the abstract property brand.
  • We also provide a concrete implementation for the abstract method startEngine().

Now, let's use the Car class to demonstrate the use of both the abstract and concrete members:

Code:

Output:

Here, you can see that both the abstract and concrete members of the Vehicle abstract class are utilized in the Car subclass. The abstract members are overridden with concrete implementations in the subclass.

Overriding a Non-abstract Open Member with an Abstract Member

To override a non-abstract open member with an abstract member, you need an open class that contains the member, an abstract class that inherits from the open class, and a concrete class that provides an implementation for the abstract member.

First, we have an open class Animal with an open member, makeSound():

Code:

Now, we create an abstract class AbstractCat that inherits from Animal and overrides the makeSound() function with an abstract declaration:

Code:

In this abstract class, we use the abstract keyword to declare an abstract version of the makeSound() function, effectively making it mandatory for subclasses to provide an implementation.

Finally, we create a concrete class DomesticCat that extends AbstractCat and provides a concrete implementation for makeSound():

Code:

Now, let's use these classes:

Output:

Using Multiple Derived Classes

Abstract classes are often used when you have a common set of characteristics and behaviors shared among multiple related classes. Using multiple derived classes in combination with an abstract class can help you organize and manage these classes effectively. Let's illustrate this concept with an example.

Suppose you're building a simple application to model different shapes. You have an abstract class Shape and multiple derived classes representing specific types of shapes:

Code:

Explanation:

In this example:

We have an abstract class Shape with two abstract methods: area() and perimeter().

We then have three derived classes: Circle, Rectangle, and Triangle. Each of these classes inherits from the Shape abstract class and provides concrete implementations for the area() and perimeter() methods specific to their shapes.

Now, you can use these classes to create instances of various shapes and calculate their areas and perimeters:

Code:

Output:

Using an abstract class like Shape as a common base class for different shapes allows you to treat them uniformly and take advantage of polymorphism to call shape-specific methods like area() and perimeter(). This structure provides a clean and organized way to work with multiple derived classes.

Real-life Scenarios of Abstract Classes

Consider the following example:

Code:

Explanation:

In this scenario:

BankAccount is an abstract class representing common attributes and methods for all types of bank accounts. It has abstract methods deposit() and withdraw() which need to be implemented by concrete subclasses. It also has a non-abstract displayBalance() method with a default implementation.

SavingsAccount and CheckingAccount are concrete classes representing specific account types. They inherit from the BankAccount class and provide their implementations for the deposit() and withdraw() methods. Additionally, they override the displayBalance() method to provide account-specific information.

Using this model, you can create instances of SavingsAccount and CheckingAccount and interact with them as follows:

Code:

When you run the program, you'll get output that demonstrates the behavior of different bank accounts:

Output:

This shows how an abstract class (BankAccount) serves as a template for different types of bank accounts, allowing you to model common and distinct behaviors for each account type.

Advantages and Disadvantages of Abstract Classes in Kotlin

Advantages

  • Abstraction:
    An abstract class in Kotlin offers a means to establish a shared contract across various classes while leaving out the specific implementation details. This facilitates the creation of abstractions, enhancing code modularity and maintainability.

  • Polymorphism:
    An abstract class in Kotlin enables the creation of objects belonging to different types but adhering to a common interface. This empowers polymorphic behavior, allowing for flexibility and compatibility among diverse objects.

  • Code Reusability:
    An abstract class in Kotlin supports code reuse by enabling multiple classes to extend the same abstract class and inherit its abstract methods and properties. This encourages efficient and shared code implementation.

  • Implementing Common Behavior:
    An abstract class in Kotlin provides a mechanism to enforce consistent behavior among their subclasses, minimizing the need to redundantly write similar code in each subclass.

Disadvantages:

  • Restricted Instantiation:
    An abstract class in Kotlin does not permit direct instantiation, thus imposing restrictions on how objects are created.

  • Increased Complexity:
    The usage of an abstract class in Kotlin can introduce complexity into your code, particularly when dealing with numerous classes that extend multiple abstract classes.

Conclusion

  • An abstract class in Kotlin provides a way to encapsulate and abstract shared behaviors and characteristics in a structured manner, making code more organized and easier to understand.
  • An abstract class in Kotlin can not be instantiated. It can have both abstract and concrete members. The sub-classes implementing the abstract class in Kotlin are expected to provide an implementation of these abstract members.
  • An abstract class in Kotlin enables the use of polymorphism, allowing different subclasses to conform to a common interface. This flexibility enhances the code's adaptability, making it easier to add new classes that fit within the established structure.
  • An abstract class in Kotlin promotes code reuse by allowing multiple related classes to inherit common properties and methods. This reduces redundancy, maintains code consistency, and accelerates development by sharing and extending existing code.