Object-Oriented JavaExtra· 35 min read

Abstract Classes & Abstraction

An abstract class is a half-finished blueprint: it shares real code but forces children to fill in the missing pieces.

What you will learn

  • Write an abstract class with an abstract method
  • Force subclasses to provide their own version
  • Choose between an abstract class and an interface

A blueprint you cannot build directly

Abstraction means hiding the messy details and showing only the important idea. In Java, one tool for this is an abstract class — a class marked with the word abstract.

An abstract class is a blueprint that is deliberately unfinished. You cannot create an object from it directly. Instead, other classes extend it and complete the missing parts. It is useful when several classes share some code but each must also do one thing its own way.

Think of a form template at an office. The template has fixed parts already printed (your name goes here, the date goes here) plus blank boxes everyone must fill in themselves. You never hand in the blank template — you hand in your completed copy. An abstract class is that template: it provides the printed parts (real methods) and the blank boxes (abstract methods the child must complete).

An abstract method has no body

Inside an abstract class you can have two kinds of method. A normal method has a body (code in { }). An abstract method has no body at all — just a name ending in a semicolon. It is a promise that every child must write that method.

An abstract Shape with one abstract method and one shared method
public abstract class Shape {
    String name;

    Shape(String name) {
        this.name = name;
    }

    // abstract method: no body — each child MUST provide one
    abstract double area();

    // normal method: shared by every child, with real code
    void describe() {
        System.out.println(name + " has area " + area());
    }
}

Note: Output: (No output yet — this is the blueprint. Notice area() ends in a semicolon with no curly braces: it is abstract, so Shape itself does not know how to calculate area. Each shape will. The describe() method already has real code and will be inherited as-is.)

Children fill in the blanks

Now two real shapes extend Shape. Each must write its own area(), because the parent left it abstract. They get describe() for free.

Two children that each provide their own area()
public class Circle extends Shape {
    double radius;

    Circle(double radius) {
        super("Circle");
        this.radius = radius;
    }

    @Override
    double area() {
        return 3.14159 * radius * radius;
    }
}

public class Rectangle extends Shape {
    double width, height;

    Rectangle(double width, double height) {
        super("Rectangle");
        this.width = width;
        this.height = height;
    }

    @Override
    double area() {
        return width * height;
    }
}

Note: Output: (No output yet — these classes complete the blueprint. Each writes a real area(). If Circle had forgotten to provide area(), Java would refuse to compile, because the abstract promise was not kept.)

Using them

One loop, the right area for each shape
public class Main {
    public static void main(String[] args) {
        Shape[] shapes = { new Circle(2), new Rectangle(3, 4) };

        for (Shape s : shapes) {
            s.describe();   // shared method calls each child's own area()
        }
    }
}

Note: Output: Circle has area 12.56636 Rectangle has area 12.0 The inherited describe() ran for both, but each time it called the child own area(). The Circle used the radius formula and the Rectangle multiplied width by height. We could store both in a Shape[] array even though Shape can never be built on its own.

Abstract class vs interface

Both let you promise methods, but they answer different questions. Use this table to choose:

Abstract classInterface
Says: this IS A kind of thing (a Circle IS A Shape)Says: this CAN DO something (a class is Playable)
Can hold real code AND fields/constructorsMostly just method names (a contract)
A class can extend only ONEA class can implement MANY
Good when children share codeGood when unrelated classes share an ability

Watch out: You cannot write new Shape("x") — Java stops you, because an abstract class is incomplete. You can only create objects of the finished children (Circle, Rectangle). The whole point is that Shape on its own is not a real, usable thing.

Tip: A simple rule of thumb: reach for an abstract class when your children are clearly the same family and share code. Reach for an interface when you just want different, unrelated classes to share one ability.

Q. What is special about an abstract method?

Answer: An abstract method is just a name with no code. Each subclass must write the real version, or the subclass will not compile — that is how an abstract class forces the missing pieces to be filled in.

✍️ Practice

  1. Write an abstract Animal class with an abstract method sound() and a normal method describe(). Extend it with Dog and Cat.
  2. Try writing new Animal() and confirm Java refuses to compile it.

🏠 Homework

  1. Build an abstract Employee class with an abstract salary() method and a shared printPayslip() method. Add two subclasses (Manager, Intern) that each compute salary differently, then loop over an array of them.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →