Abstract Classes and Interfaces

Basic Java
≈ 4 min read

After inheritance and polymorphism, an important question appears: how do you describe a common type when some behavior can already be implemented, while some must be left for specific classes to provide? Java has abstract classes and interfaces for this purpose. They help define common rules for different implementations, but they do it in different ways.

An abstract class is a foundation for a family of classes

An abstract class is declared with abstract. You cannot create its object directly, but it can store state, have constructors, regular methods, and methods without an implementation — abstract methods.

abstract class Animal {
    private String name;

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

    String getName() {
        return name;
    }

    abstract String sound();
}

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

    @Override
    String sound() {
        return "Woof";
    }
}

Animal already has common state and a ready-to-use getName() method, but the specific sound is not known in advance. That is why sound() only defines a requirement, while Dog provides the implementation.

An abstract method has no body. If a regular class extends an abstract class, it must implement all inherited abstract methods. Otherwise, that class must also be abstract.

An interface is a contract of capabilities

An interface is useful when what matters is not the common origin of objects, but what they can do. A class connects an interface with implements and takes responsibility for fulfilling its contract.

interface Payable {
    double calculatePayment();
}

class Freelancer implements Payable {
    private double amount;

    Freelancer(double amount) {
        this.amount = amount;
    }

    @Override
    public double calculatePayment() {
        return amount;
    }
}

The calculatePayment() method in the interface is declared without a body. Such a method is implicitly public abstract, so its implementation in the class must be public. The interface itself, just like an abstract class, cannot be created with new.

The main advantage of an interface becomes especially clear when one class needs several independent capabilities. A class can extend only one class, but it can implement multiple interfaces.

interface Printable {
    void print();
}

interface Scannable {
    void scan();
}

class OfficeDevice implements Printable, Scannable {
    @Override
    public void print() {
        System.out.println("Printing");
    }

    @Override
    public void scan() {
        System.out.println("Scanning");
    }
}

An interface can contain ready-made behavior

An interface is not necessarily just a set of methods without bodies. A method with the default modifier can have an implementation that classes receive automatically and can override when necessary.

interface Loggable {
    default void log(String message) {
        System.out.println(message);
    }
}

This makes it possible to add common behavior to a contract without turning the interface into a base class. At the same time, an interface is still not intended to store the ordinary state of each object.

Abstract class or interface?

Use the meaning of the relationship between classes as your guide. An abstract class fits when related objects have a common foundation: state, constructors, and part of a shared implementation. An interface fits when you need to describe a separate capability or contract that can be fulfilled even by classes from different hierarchies.

  • Abstract class: “these objects belong to one family and share a common foundation.”
  • Interface: “these objects promise to be able to do a particular thing.”

These approaches do not compete with each other. One class can extend an abstract class and implement one or more interfaces at the same time — this is how flexible models are often built in Java.