Codectionary / Developer documentation / Java

Abstract Classes

An abstract class is a class that cannot be instantiated directly and may contain both fully implemented methods and abstract methods (declared without a body, which subclasses must implement). Abstract classes sit between interfaces and regular classes: like an interface, they define a contract; like a regular class, they can hold state (fields) and provide shared, already-implemented behavior.

Syntax

abstract class ClassName {\n  abstract returnType methodName();\n}

Examples

Basic Abstract Class

Defining a base class that mixes concrete and abstract methods.

public abstract class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public abstract void makeSound();  // no body - subclasses must implement

    public void sleep() {  // concrete method, shared by all subclasses
        System.out.println(name + " is sleeping");
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " says: Woof!");
    }
}

// Animal a = new Animal("Generic");  // Error - can't instantiate abstract class
Dog dog = new Dog("Rex");
dog.makeSound();
dog.sleep();

Enforcing a Common Structure

Multiple subclasses implementing the same abstract method differently.

abstract class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    public abstract double calculateBonus();

    public double totalPay() {
        return baseSalary + calculateBonus();
    }
}

class Manager extends Employee {
    public Manager(String name, double baseSalary) {
        super(name, baseSalary);
    }

    @Override
    public double calculateBonus() {
        return baseSalary * 0.2;
    }
}

class Developer extends Employee {
    public Developer(String name, double baseSalary) {
        super(name, baseSalary);
    }

    @Override
    public double calculateBonus() {
        return baseSalary * 0.1;
    }
}

Employee m = new Manager("John", 60000);
System.out.println(m.totalPay());  // 72000.0

Abstract Class vs Interface

A quick illustration of when each is more appropriate.

// Interface: unrelated classes sharing a capability, no shared state
interface Flyable {
    void fly();
}

// Abstract class: closely related classes sharing state AND behavior
abstract class Bird {
    protected String species;

    public Bird(String species) {
        this.species = species;
    }

    public abstract void layEggs();

    public void breathe() {
        System.out.println(species + " is breathing");
    }
}

class Eagle extends Bird implements Flyable {
    public Eagle() {
        super("Eagle");
    }

    public void layEggs() {
        System.out.println("Eagle laying eggs");
    }

    public void fly() {
        System.out.println("Eagle soaring high");
    }
}

Best practices

  • Use an abstract class when subclasses share both state (fields) and some common implemented behavior, not just a method signature
  • Use an interface instead when unrelated classes just need to share a capability, with no shared fields or implementation
  • A class can only extend one abstract class but can implement multiple interfaces - factor that into your design choice
  • Make a method abstract only when every subclass genuinely needs its own distinct implementation - otherwise provide a sensible default in the abstract class itself

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading