Java Interfaces and Abstract Classes

Java interfaces and abstract classes both describe what a type can do without giving a complete implementation. They are the main tools for writing flexible code that depends on behaviour rather than on specific classes.

Abstract Classes

An abstract class cannot be instantiated. It can contain normal fields and methods plus abstract methods that have no body and must be implemented by subclasses.

abstract class Employee {
    protected final String name;

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

    abstract double monthlyPay();

    void printPay() {
        System.out.printf("%s earns %.0f%n", name, monthlyPay());
    }
}

class Salaried extends Employee {
    private final double salary;
    Salaried(String name, double salary) { super(name); this.salary = salary; }
    @Override double monthlyPay() { return salary / 12; }
}

class Hourly extends Employee {
    private final double rate; private final int hours;
    Hourly(String name, double rate, int hours) { super(name); this.rate = rate; this.hours = hours; }
    @Override double monthlyPay() { return rate * hours; }
}

public class Main {
    public static void main(String[] args) {
        new Salaried("Amna", 120_000).printPay();
        new Hourly("Omar", 25, 160).printPay();
    }
}
Amna earns 10000
Omar earns 4000

Interfaces

An interface is a contract: a list of methods a class promises to provide. A class implements an interface, and one class can implement several. Interfaces can also have default methods with a body.

interface Payable {
    double amountDue();

    default String summary() {
        return String.format("Due: %.2f", amountDue());
    }
}

interface Printable {
    void print();
}

class Invoice implements Payable, Printable {
    private final double total;
    Invoice(double total) { this.total = total; }

    @Override public double amountDue() { return total * 1.17; }
    @Override public void print() { System.out.println("Invoice " + summary()); }
}

public class Main {
    public static void main(String[] args) {
        Payable p = new Invoice(100);
        System.out.println(p.summary());
        ((Printable) p).print();
    }
}
Due: 117.00
Invoice Due: 117.00

Sealed Interfaces (Java 17+)

A sealed type lists exactly which classes may implement it. The compiler then knows every possible subtype, which makes switch pattern matching exhaustive without a default.

sealed interface Payment permits Card, Cash {}
record Card(String last4) implements Payment {}
record Cash(double tendered) implements Payment {}

public class Main {
    static String describe(Payment p) {
        return switch (p) {
            case Card c -> "Card ending " + c.last4();
            case Cash c -> "Cash " + c.tendered();
        };
    }

    public static void main(String[] args) {
        System.out.println(describe(new Card("4242")));
        System.out.println(describe(new Cash(50)));
    }
}
Card ending 4242
Cash 50.0

Interface vs Abstract Class

  • Use an interface to define a capability that unrelated classes can share (Comparable, Runnable).
  • Use an abstract class when subclasses share state (fields) and common code.
  • A class can implement many interfaces but extend only one class.
  • Interfaces cannot have instance fields; abstract classes can.
  • In practice, start with an interface and add an abstract base class only if it removes real duplication.

Frequently asked questions

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

An abstract class can hold fields, constructors and shared code, and a class can extend only one. An interface defines a contract without instance state, and a class can implement many.

Can an interface have method bodies in Java?

Yes. Since Java 8 interfaces can have default and static methods, and since Java 9 private methods too.

Can you create an object of an abstract class?

No, not directly. You create an object of a concrete subclass, or an anonymous class that implements the abstract methods.