Java Tutorial · Object-Oriented Java · Lesson 22 of 37

Java Abstract Classes and Interfaces

Define contracts with interfaces and partial implementations with abstract classes.

Interfaces

An interface defines what a class can do. Classes implements it and must provide every abstract method. Interfaces can also have default methods with a body:

Example 1
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Notifier> channels = List.of(new EmailNotifier(), new SmsNotifier());
        for (Notifier n : channels) {
            System.out.println(n.send("Your order shipped"));
            System.out.println(n.sendUrgent("Payment failed"));
        }
    }
}

interface Notifier {
    String send(String message);

    default String sendUrgent(String message) {
        return send("URGENT: " + message);
    }
}

class EmailNotifier implements Notifier {
    public String send(String message) { return "Email -> " + message; }
}

class SmsNotifier implements Notifier {
    public String send(String message) { return "SMS -> " + message; }
}

Output

Email -> Your order shipped
Email -> URGENT: Payment failed
SMS -> Your order shipped
SMS -> URGENT: Payment failed

Run this on your computer — see “Get Started” for setup.

Abstract classes

An abstract class can't be instantiated. It can hold fields, constructors and concrete methods, plus abstract methods that subclasses must implement:

Example 2
public class Main {
    public static void main(String[] args) {
        Shape[] shapes = {new Circle(1), new Rectangle(2, 3)};
        for (Shape s : shapes) {
            System.out.println(s.describe());
        }
    }
}

abstract class Shape {
    abstract double area();

    String describe() {
        return String.format("%s with area %.2f", getClass().getSimpleName(), area());
    }
}

class Circle extends Shape {
    private final double r;
    Circle(double r) { this.r = r; }
    double area() { return Math.PI * r * r; }
}

class Rectangle extends Shape {
    private final double w, h;
    Rectangle(double w, double h) { this.w = w; this.h = h; }
    double area() { return w * h; }
}

Output

Circle with area 3.14
Rectangle with area 6.00

Run this on your computer — see “Get Started” for setup.

Sealed types (Java 17+)

sealed restricts which classes may implement an interface — the compiler then knows every case, which works beautifully with pattern-matching switch.

Example 3
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Payment> payments = List.of(new Card("4242"), new BankTransfer("DE89..."), new Cash());
        for (Payment p : payments) {
            String text = switch (p) {
                case Card c -> "card ending " + c.last4();
                case BankTransfer b -> "transfer from " + b.iban();
                case Cash c -> "cash";
            };   // no default needed: the compiler knows all cases
            System.out.println(text);
        }
    }
}

sealed interface Payment permits Card, BankTransfer, Cash {}
record Card(String last4) implements Payment {}
record BankTransfer(String iban) implements Payment {}
record Cash() implements Payment {}

Output

card ending 4242
transfer from DE89...
cash

Run this on your computer — see “Get Started” for setup.

Test yourself

Which keyword does a class use to implement an interface?

  1. extends
  2. implements
  3. uses
  4. inherits
Show answer

Answer: implements