Abstract Class in Java – When and Why to Use It?

  • Last Updated: January 6, 2026
  • By: javahandson
  • Series
img

Abstract Class in Java – When and Why to Use It?

Abstract Class in Java – When and Why to Use It is a question that many developers struggle with while learning Core Java. While it is easy to memorize the definition of an abstract class, understanding when to use an abstract class in Java and why it exists is far more important for writing clean and maintainable code. Abstract classes help solve real design problems by allowing partial implementation, enforcing mandatory behavior in subclasses, and accurately modeling real-world hierarchies. In this article, we will focus on why abstract classes are needed, when they are the right choice over normal classes or interfaces, and how they work with inheritance, using simple explanations and practical examples.

1. Introduction to Abstract classes in Java

An abstract class in Java is a class that cannot be instantiated and is intended to be extended by other classes. It is used when we want to define a common base structure but do not want to provide a complete implementation for all behaviors. In simple terms, an abstract class represents an incomplete idea that child classes must complete.

Java introduced abstract classes to support partial abstraction. In many real-world scenarios, we want to share common code across related classes, but at the same time, we want to force those classes to implement certain methods in their own way. Abstract classes solve this problem by allowing both implemented methods and methods without implementation. This helps in designing cleaner, more maintainable, and more flexible applications.

The key difference between a normal class and an abstract class is that a normal class is fully concrete and can be instantiated directly, whereas an abstract class cannot be instantiated and may contain abstract methods. A normal class cannot force subclasses to implement any method, but an abstract class can define rules that every subclass must follow. This makes abstract classes more suitable for defining frameworks and base classes.

Abstract classes closely match real-world concepts. For example, a Vehicle is a general concept, but we cannot actually use a vehicle unless it is a Car or a Bike. Similarly, a Payment defines the idea of paying, but the actual process differs for credit cards, UPI, or net banking. A Shape can define that an area exists, but each shape calculates it differently. In all these cases, the abstract class defines what should be done, while the concrete classes define how it is done.

In essence, an abstract class allows Java developers to model real-world hierarchies accurately by combining shared behavior with enforced structure, without allowing misuse through direct object creation.

2. Why do we need Abstract classes?

Abstract classes are needed because pure inheritance using normal classes is often not enough to model real-world problems correctly. With normal inheritance, a parent class must provide complete implementations for all its methods. This can lead to situations where the parent class contains methods that do not make sense for all child classes, or where subclasses inherit behavior they should not have.

For example, consider a Vehicle class created using normal inheritance:

class Vehicle {
    void move() {
        System.out.println("Vehicle is moving");
    }
}

Now, suppose we create different types of vehicles:

class Car extends Vehicle { }
class Boat extends Vehicle { }

At this point, the #move() method in the parent class becomes a problem. A car moves on roads, while a boat moves on water. However, because Vehicle is a normal class, it is forced to provide an implementation of #move(). This generic implementation may not make sense for all child classes, and subclasses may accidentally inherit or use behavior that is incorrect for them.

Developers often try to fix this by:

  • Writing a vague or meaningless implementation in the parent class
  • Overriding the method in every subclass, even when the parent implementation should never exist
  • Leaving empty method bodies, which is poor design

Abstract classes solve this by allowing the parent class to declare the method without implementing it, forcing each subclass to define its own meaningful behavior.

abstract class Vehicle {
    abstract void move();
}

Now each subclass clearly defines how it moves, and the design correctly represents the real world without unnecessary or misleading logic in the parent class.

One of the biggest advantages of abstract classes is partial implementation. In many cases, some logic is common across all subclasses, while some logic must vary. Abstract classes allow us to implement the common parts once and leave the variable parts abstract. This avoids code duplication while still keeping the design flexible and clean.

Abstract classes are also useful when we want to force subclasses to follow a contract without relying only on interfaces. By declaring abstract methods, the parent class guarantees that every subclass provides its own implementation. At the same time, the parent class can include shared fields, helper methods, and default behavior, which interfaces traditionally could not provide.

Interfaces alone are not always sufficient. When we need:

  • Shared state using instance variables
  • Constructors to initialize common data
  • Reusable method implementations
  • Strong “is-a” relationship with controlled inheritance

An abstract class becomes the better choice. Interfaces define what a class can do, but abstract classes define what a class is, along with shared behavior.

In short, abstract classes exist to bridge the gap between rigid inheritance and pure abstraction, giving developers the flexibility to design systems that are both reusable and enforce correct implementation.

3. Declaring an Abstract class

An abstract class in Java is declared using the abstract keyword. It is used when a class is meant to act as a base class and should not be instantiated directly. The syntax looks similar to a normal class, with the key difference being that it may contain abstract methods, which do not have a method body.

An abstract class can contain both abstract and non-abstract methods. Abstract methods only declare what a method should do, while non-abstract (concrete) methods provide actual implementation. This allows the abstract class to define common behavior that can be reused, while still leaving some behavior to be implemented by subclasses.

There are a few important rules to remember about abstract classes:

  • They can have constructors, which are used to initialize common state when a subclass object is created
  • They can have instance variables, just like normal classes
  • They can have static methods and static blocks, which belong to the class itself
  • They cannot be instantiated, but they can be used as reference types

A simple example of an abstract class is shown below:

abstract class Vehicle {

    int speed; // instance variable

    Vehicle(int speed) { // constructor
        this.speed = speed;
    }

    abstract void move(); // abstract method

    void start() { // non-abstract method
        System.out.println("Vehicle started at speed " + speed);
    }

    static void info() { // static method
        System.out.println("This is a vehicle");
    }
}

In this example, the Vehicle class defines common data and behavior shared by all vehicles, while leaving the #move() method abstract so that each subclass can provide its own specific implementation. This is the typical and recommended way to declare and use abstract classes in Java.

4. Abstract methods explained

An abstract method is a method that is declared without an implementation. It only defines the method signature and represents a behavior that must be provided by subclasses. Abstract methods are declared using the abstract keyword and can exist only inside abstract classes.

Abstract methods do not have a body because the abstract class does not know how the behavior should be implemented. The responsibility of providing the actual logic is intentionally deferred to the child classes. This helps avoid meaningless or incorrect implementations in the parent class and ensures that each subclass defines behavior appropriate to its context.

A key rule in Java is that every concrete subclass must implement all inherited abstract methods. This is a mandatory override rule enforced at compile time. It guarantees that no incomplete object can be created and that all required behaviors are properly defined before an object is used.

If a subclass does not implement all abstract methods, Java enforces one of the following:

  • The subclass must itself be declared as abstract, or
  • The compiler will throw an error, preventing object creation
abstract class Vehicle {
    abstract void move();
}

class Car extends Vehicle {
    @Override
    void move() {
        System.out.println("Car moves on roads");
    }
}

If Car does not implement #move(), it must be declared as abstract. Otherwise, the code will fail to compile. This strict rule ensures that abstract methods truly act as a contract and that all concrete classes provide complete and meaningful implementations.

5. Can we create an object of an Abstract class?

No, we cannot create an object of an abstract class in Java. This is because an abstract class represents an incomplete concept and may contain abstract methods whose implementation is not defined. Allowing object creation would mean creating an object with unfinished behavior, which Java intentionally prevents.

Instantiation is not allowed at compile time. When we try to create an object of an abstract class using the new keyword, the compiler throws an error because it cannot guarantee that all required methods are implemented. This check happens before the program runs, ensuring type safety and correct design.

Example of an invalid instantiation:

abstract class Vehicle {
    abstract void move();
}

public class Test {
    public static void main(String[] args) {
        Vehicle v = new Vehicle(); // compile-time error
    }
}

The important concept to understand here is that while we cannot create an object of an abstract class, we can create a reference variable of an abstract class type. This reference can point to an object of any concrete subclass. This is a core idea behind polymorphism.

Vehicle v = new Car(); // valid

In this case:

  • Vehicle is the reference type
  • The car is the actual object created in memory
  • Method calls are resolved at runtime based on the object type

This design allows Java to enforce abstraction while still enabling flexible and extensible code using polymorphism.

6. Constructors in Abstract classes

Abstract classes can have constructors, even though they cannot be instantiated directly. This may seem confusing at first, but constructors in abstract classes exist to initialize common state that will be shared by all subclasses. When a subclass object is created, the abstract class constructor is automatically executed as part of the object creation process.

The execution order of constructors is always well-defined. When we create an object of a concrete subclass:

  • The abstract class constructor executes first
  • Then the child class constructor executes

This order ensures that the parent part of the object is properly initialized before the child-specific initialization begins.

package com.javahandson;

abstract class Vehicle {
    int speed;
    Vehicle(int speed) {
        this.speed = speed;
        System.out.println("Vehicle Parent constructor called : " + this.speed);
    }
}
class Car extends Vehicle {
    Car(int speed) {
        super(speed);
        System.out.println("Car Child constructor called");
    }
}
public class Main {
    public static void main(String[] args) {
        Car car = new Car(70);
    }
}
Output:
Vehicle Parent constructor called : 70
Car Child constructor called

When we create a Car object, the abstract class constructor runs first to initialize the speed field, followed by the Car constructor. This makes abstract class constructors especially useful for setting up common fields, validations, or default values that every subclass must inherit.

In practice, constructors in abstract classes are commonly used to:

  • Initialize shared instance variables
  • Enforce mandatory data during object creation
  • Reduce duplication of initialization logic in subclasses

Although we cannot create an object of an abstract class directly, its constructor plays a critical role in building fully initialized subclass objects.

7. Abstract class vs Interface (Brief comparison)

Abstract classes allow partial implementation, meaning they can contain both abstract methods and concrete methods with shared logic. They are useful when related classes share common state and behavior.

Interfaces, on the other hand, focus on defining a pure contract. They specify what a class can do rather than what it is, and are commonly used to achieve multiple inheritance of behavior.

Key differences at a glance:

  • Abstract classes can have constructors and instance variables, whereas interfaces cannot maintain instance state
  • Abstract classes support code reuse through inheritance, while interfaces emphasize capability and role-based design
  • A class can extend only one abstract class, but it can implement multiple interfaces

A detailed comparison and design guidelines are covered separately in the Interface article.

8. Abstract classes and inheritance

Abstract classes fully participate in Java’s inheritance model, but they still follow Java’s single inheritance rule. A class can extend only one class at a time, whether that class is abstract or concrete. This restriction avoids ambiguity and keeps the inheritance hierarchy simple and predictable.

abstract class Vehicle {
    abstract void move();
}

abstract class Machine {
    abstract void start();
}

// Not allowed: multiple inheritance of classes
class Car extends Vehicle, Machine {
    @Override
    void move() {
        System.out.println("Car moves");
    }

    @Override
    void start() {
        System.out.println("Car starts");
    }
}

The above code will not compile, because Java does not allow a class to extend more than one class, even if both parent classes are abstract. This restriction exists to avoid ambiguity in method resolution and state inheritance.

A class must choose one parent class in the inheritance hierarchy. If multiple behaviors are required, Java expects developers to use interfaces alongside abstract classes to keep the design clean and predictable.

Abstract classes work very well with multilevel inheritance. An abstract class can be extended by another abstract class, and the chain can continue until a concrete class finally provides implementations for all remaining abstract methods. This allows behavior to be gradually refined as we move down the hierarchy.

It is also common for an abstract class to extend another abstract class. In such cases, the child abstract class may:

  • Implement some of the abstract methods
  • Leave the remaining ones unimplemented
  • Add new abstract methods of its own

This enables partial implementation in between levels of inheritance. Each level can contribute to behavior or enforce new rules without being forced to complete the entire implementation.

package com.javahandson;

abstract class Vehicle {
    abstract void move();
}

abstract class MotorVehicle extends Vehicle {
    void startEngine() {
        System.out.println("Engine started");
    }
}

class Car extends MotorVehicle {
    @Override
    void move() {
        System.out.println("Car moves on roads");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.startEngine();
        car.move();
    }
}
Output:
Engine started
Car moves on roads

9. Common Mistakes with Abstract Classes

1. Forgetting to implement abstract methods – Every concrete subclass must implement all abstract methods from its parent abstract class. If even one method is missing, the subclass must be declared abstract; otherwise, the code will not compile.

2. Trying to create objects of an abstract class – Abstract classes cannot be instantiated because they may contain incomplete behavior. Attempting to create an object using the new keyword results in a compile-time error.

3. Overusing abstract classes instead of interfaces – Abstract classes should be used when shared state or common implementation is required. If the goal is only to define a contract or support multiple inheritance, interfaces are usually the better choice.

4. Confusing abstract methods with default methods – Abstract methods belong to abstract classes and have no implementation, while default methods belong to interfaces and provide an implementation. Mixing these concepts often leads to poor design decisions.

10. Conclusion

Abstract classes are a fundamental concept in Core Java that help in designing clean, flexible, and well-structured object-oriented applications. They allow developers to define a common base with shared behavior while still enforcing certain methods to be implemented by subclasses. This balance between abstraction and implementation makes abstract classes especially useful for modeling real-world hierarchies.

By preventing direct object creation, supporting constructors, and working seamlessly with inheritance, abstract classes encourage correct design decisions and reduce the chances of misuse. When used appropriately, they improve code reusability, readability, and maintainability.

In summary, abstract classes should be chosen when we need shared state, partial implementation, and controlled inheritance. Understanding when and how to use them not only strengthens our Core Java fundamentals but also prepares us well for real-world development and Java interviews.

11. Abstract class interview questions (FAQ’s)

Can an abstract class have a main method?

Yes. An abstract class can have a main method, and it can be executed like a normal class. This is possible because the main method is static and does not require object creation.

Can an abstract class have static methods?

Yes. Abstract classes can have static methods because static methods belong to the class, not to instances. These methods can be called using the class name.

Can an abstract class implement an interface?

Yes. An abstract class can implement an interface without providing implementations for all interface methods. In such cases, the abstract class passes the responsibility of implementation to its concrete subclasses.

Can an abstract class extend another abstract class?

Yes. An abstract class can extend another abstract class. It may choose to implement some abstract methods or leave them unimplemented, remaining abstract itself.

Why is multiple inheritance not allowed with abstract classes?

Multiple inheritance of classes is not allowed to avoid ambiguity in method resolution and state inheritance. If two parent classes contain the same method or instance variables, the compiler cannot determine which one to inherit, leading to confusion. Java solves this problem by allowing multiple inheritance through interfaces instead.

Leave a Comment