Abstraction: Decoding Abstract Classes in Java

Arshi Saxena - Oct 28 - - Dev Community

In this post, we explore Abstract Classes, an essential part of abstraction in Java. We'll build on concepts discussed earlier and examine how abstraction simplifies complex systems. Abstract classes serve as a blueprint for other classes, allowing us to focus only on relevant details while hiding unnecessary complexity.

Let’s dive deeper into what abstract classes are, why they exist, and how they are used.


What is an Abstract Class?

An abstract class is a class that cannot be instantiated on its own. It’s designed to be extended by subclasses that provide concrete implementations for its abstract methods. In other words, an abstract class lays out the foundation for its subclasses, enabling code reuse and enforcing structure.

Key Features of Abstract Classes:

  • Defined using the abstract keyword.

  • Can contain abstract methods (methods without a body) that must be implemented by subclasses.

  • Can also have concrete methods with full implementations.

  • Can declare constructors, fields, and non-abstract methods.

  • Cannot be instantiated directly.


Why Abstract Classes?

Abstract classes allow developers to hide unnecessary implementation details from the user while ensuring that certain methods are implemented by all subclasses. They act as half-defined templates and encourage code reuse by providing shared functionality in the base class.


Example: Employee and Manager

To demonstrate how abstract classes work, let’s look at the following example involving an abstract EmployeeParent class and its ManagerChild subclass. The parent class holds shared functionality, while the child class completes the implementation with specific details like performance bonuses.

EmployeeParent.java

package oops.abstract_class;

public abstract class EmployeeParent {
    private int id, depId;
    private String name;
    private double basicSal;

    public EmployeeParent(int id, String name, int deptId, double basicSal) {
        this.id = id;
        this.depId = deptId;
        this.name = name;
        this.basicSal = basicSal;
    }

    // Abstract method to be implemented by subclasses.
    protected abstract double computeNetSalary();

    protected double getBasicSal() {
        return basicSal;
    }

    @Override
    public String toString() {
        return "EmployeeParent [id=" + id + ", depId=" + depId +
               ", name=" + name + ", basicSal=" + basicSal + "]";
    }
}
Enter fullscreen mode Exit fullscreen mode

ManagerChild.java

package oops.abstract_class;

public class ManagerChild extends EmployeeParent {
    private double perfBonus;

    public ManagerChild(int id, String name, int deptId, double basicSal, double perfBonus) {
        // Calling the constructor of the abstract class.
        super(id, name, deptId, basicSal);
        this.perfBonus = perfBonus;
    }

    // Implementing the abstract method from EmployeeParent.
    @Override
    public double computeNetSalary() {
        return getBasicSal() + perfBonus;
    }

    @Override
    public String toString() {
        return "ManagerChild [perfBonus=" + perfBonus + "\n" + super.toString() + "]";
    }

    public static void main(String[] args) {
        ManagerChild manager = new ManagerChild(1, "Arshi", 2, 10000, 1890);
        System.out.println(manager);
        System.out.println("Net Salary: " + manager.computeNetSalary());

        // Abstract class cannot be instantiated 
        EmployeeParent employee = new EmployeeParent(); // Compile Error
    }
}
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Example

In the above code:

  1. EmployeeParent is the abstract class that defines the structure for its subclasses.

  2. It contains both concrete methods (like toString and getBasicSal) and an abstract method (computeNetSalary), which must be implemented by any subclass.

  3. ManagerChild extends EmployeeParent and provides the specific logic for computing the net salary, including the performance bonus.

  4. The abstract class constructor is invoked via the super() call in the child class constructor, as the abstract class cannot be instantiated directly.


When Should You Use Abstract Classes?

  • Code Reusability: When multiple classes share common fields and behavior.

  • Enforce Structure: When you want to mandate the implementation of certain methods in subclasses.

  • Partial Implementation: When some logic can be shared among classes, while specific logic varies.

  • Use Case Example: You could have an abstract Shape class with common properties (like color) and abstract methods (like getArea), which different shapes (Circle, Rectangle) would implement differently.


Conclusion

Abstract classes play a crucial role in Java by providing a balance between full abstraction and concrete implementation. They allow developers to focus on what’s necessary while hiding intricate details from the user. Understanding and effectively using abstract classes is an important step toward mastering object-oriented programming.

Stay tuned for the next post in the series, where we explore interfaces and how they differ from abstract classes!


Related Posts

Happy Coding!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .