Classes, records and interfaces

Constructors, access modifiers, inheritance, and the modern shortcuts — records, enums and interfaces with defaults.

A class

public class Account {
    private final String owner;      // encapsulated state
    private long balance;

    public Account(String owner, long opening) {
        this.owner = owner;
        this.balance = opening;
    }

    public void deposit(long amount) {
        if (amount <= 0) throw new IllegalArgumentException("amount must be positive");
        balance += amount;
    }

    public long balance() { return balance; }
}
ModifierVisible to
privateThe class only
(default)The package
protectedPackage + subclasses
publicEveryone

Records and enums

A record is a compact immutable data carrier: the compiler generates the constructor, accessors, equals, hashCode and toString.

public record Point(int x, int y) {
    public Point {
        // compact constructor: validate
        if (x < 0 || y < 0) throw new IllegalArgumentException("negative coords");
    }
    public double distanceFromOrigin() { return Math.hypot(x, y); }
}

public enum Status { ACTIVE, SUSPENDED, CLOSED }

Interfaces and inheritance

A class can extend one class but implement many interfaces, and interfaces may provide default method bodies. Favour composition over deep hierarchies.

public interface Auditable {
    void audit(String action);
    default String label() { return getClass().getSimpleName(); }
}

public sealed interface Shape permits Circle, Square {}
public record Circle(double r) implements Shape {}
public record Square(double side) implements Shape {}

double area(Shape s) {
    return switch (s) {                       // pattern matching (Java 21)
        case Circle c -> Math.PI * c.r() * c.r();
        case Square q -> q.side() * q.side();
    };
}
💡
sealed types let the compiler prove your switch handles every case — no default branch, no silent omission when someone adds a variant.

FAQ

Class or record?
Records for immutable data with no behaviour beyond derived values. Classes when you need mutable state, inheritance or many methods.
Why does @Override matter?
It makes the compiler verify you are actually overriding something — catching typos like a wrong parameter list that silently creates an overload.

Java: getting started Java collections

Last refreshed 2026-09-17.