Home/Learn/Java A–Z/Abstract Classes

Abstract Classes

Beginner
OOP & Advanced Classes

Use abstract classes to share partial implementations across related subclasses while enforcing a contract through abstract methods.

Overview

An abstract class sits between a concrete class and an interface. It can contain both abstract methods (no body — subclasses must implement) and concrete methods (with a body — subclasses inherit for free). Abstract classes can have constructors, fields of any access level, and state — things interfaces cannot have. The canonical use case is the Template Method pattern: define the skeleton of an algorithm in the abstract class and let subclasses fill in the specific steps.

Defining & Extending Abstract Classes

Declare a class abstract with the abstract keyword. Any class with at least one abstract method must also be abstract. You cannot instantiate an abstract class directly — only its concrete subclasses.

A subclass must either implement all abstract methods or declare itself abstract too. Constructors in abstract classes are called through super() in subclass constructors, even though you can't call new AbstractClass() directly.

Shape.java
public abstract class Shape {
    // Field shared by all shapes
    protected String color;

    // Constructor — called via super() in subclasses
    public Shape(String color) {
        this.color = color;
    }

    // Abstract method — subclasses MUST implement
    public abstract double area();
    public abstract double perimeter();

    // Concrete method — inherited as-is
    public void printInfo() {
        System.out.printf("%s | color=%s | area=%.2f | perimeter=%.2f%n",
            getClass().getSimpleName(), color, area(), perimeter());
    }
}

public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);           // calls Shape(String)
        this.radius = radius;
    }

    @Override public double area()      { return Math.PI * radius * radius; }
    @Override public double perimeter() { return 2 * Math.PI * radius; }
}

public class Rectangle extends Shape {
    private double width, height;

    public Rectangle(String color, double w, double h) {
        super(color);
        this.width = w; this.height = h;
    }

    @Override public double area()      { return width * height; }
    @Override public double perimeter() { return 2 * (width + height); }

    public static void main(String[] args) {
        Shape[] shapes = {
            new Circle("red", 5),
            new Rectangle("blue", 4, 6)
        };
        for (Shape s : shapes) s.printInfo();
        // Circle    | color=red  | area=78.54 | perimeter=31.42
        // Rectangle | color=blue | area=24.00 | perimeter=20.00
    }
}

Template Method Pattern

The Template Method pattern is the most natural fit for abstract classes. The abstract class defines the overall algorithm as a series of steps in a final method, and abstract (or overridable) hook methods let subclasses customise individual steps without changing the structure.

Declare the template method final so subclasses cannot override the algorithm skeleton — only the individual steps.

DataExporter.java
public abstract class DataExporter {

    // Template method — final to protect the algorithm skeleton
    public final void export(String destination) {
        connectToSource();
        Object data = fetchData();
        Object processed = processData(data);
        writeToDestination(processed, destination);
        cleanup();
        System.out.println("Export complete → " + destination);
    }

    // Abstract steps — subclasses fill in specifics
    protected abstract void connectToSource();
    protected abstract Object fetchData();
    protected abstract Object processData(Object raw);
    protected abstract void writeToDestination(Object data, String dest);

    // Hook — optional override (has a default no-op)
    protected void cleanup() { }
}

public class CsvExporter extends DataExporter {
    @Override protected void connectToSource()  { System.out.println("Connecting to DB"); }
    @Override protected Object fetchData()      { return "raw,data,rows"; }
    @Override protected Object processData(Object raw) { return ((String) raw).toUpperCase(); }
    @Override protected void writeToDestination(Object data, String dest) {
        System.out.println("Writing CSV to " + dest + ": " + data);
    }
    @Override protected void cleanup() { System.out.println("Closing DB connection"); }

    public static void main(String[] args) {
        new CsvExporter().export("/reports/output.csv");
    }
}

Abstract Class vs Interface — Decision Guide

Rule of thumb:

Use abstract class when: • You want to share code (fields, concrete methods) among closely related classes • Subclasses need access to protected state • You need constructors to enforce mandatory initialisation • The relationship is clearly IS-A with shared identity

Use interface when: • Defining a capability that unrelated classes share (Serializable, Comparable, Runnable) • You need multiple type inheritance • You want zero implementation obligation (pure contract)

In Java 8+ the gap narrowed — interfaces can have default methods. But interfaces still cannot have instance fields or constructors.

VehicleHierarchy.java
// Abstract class — shares state and behaviour
abstract class Vehicle {
    protected int speed;         // shared state
    public Vehicle(int speed) { this.speed = speed; } // constructor

    public void accelerate(int delta) { speed += delta; } // shared behaviour
    public abstract String fuelType();                    // subclass fills in
}

// Interface — pure capability, no state
interface Trackable {
    String getLocation();        // no state to share
    default void logLocation() { // convenience default
        System.out.println("Location: " + getLocation());
    }
}

// A class can extend ONE abstract class AND implement multiple interfaces
class ElectricCar extends Vehicle implements Trackable, Comparable<ElectricCar> {
    private String gpsLocation;
    private int batteryLevel;

    public ElectricCar(int speed, String loc, int battery) {
        super(speed);
        this.gpsLocation = loc;
        this.batteryLevel = battery;
    }

    @Override public String fuelType()      { return "Electric"; }
    @Override public String getLocation()   { return gpsLocation; }
    @Override public int compareTo(ElectricCar o) {
        return Integer.compare(this.batteryLevel, o.batteryLevel);
    }
}

Interactive Visualization

C = ClassA = AbstractI = Interface
CObject
Object is the root of the Java class hierarchy. Every class extends Object.
1 / 5

Key Points to Remember

  • An abstract class cannot be instantiated — only its concrete subclasses can
  • A class with even one abstract method must be declared abstract
  • Abstract class constructors run via super() — useful to enforce mandatory field initialisation
  • The Template Method pattern uses final + abstract: skeleton fixed, steps customisable
  • Abstract classes can have instance fields and constructors; interfaces cannot
  • A subclass must implement all abstract methods or declare itself abstract

Practice Abstract Classes in the Playground

Run and modify code directly in your browser - no setup needed.

Interview Questions

Sign in to ask Aria
1

Can an abstract class have a constructor? Can it be instantiated?

EasyTCS
2

What is the difference between abstract class and interface in Java 8+?

MediumAmazon
3

What is the Template Method design pattern? Give a Java example.

MediumGoogle
4

Can an abstract class implement an interface?

EasyInfosys
5

Can you declare an abstract method in a non-abstract class?

EasyWipro

Ask Aria about Abstract Classes

Your personal AI tutor — ask anything about this concept