MindIQ Academy

06 - Interfaces, Abstract Classes, Records, and Sealed Classes

A complete beginner-to-advanced guide to Java's abstraction and modern type modeling, aligned with the Oracle Certified Professional: Java SE 21 Developer (1Z0-830) exam objectives. Heavy focus on Java 21 features.


Table of Contents

  1. Abstraction Overview
  2. Interfaces
  3. Interface Members
  4. Default Methods
  5. Static Interface Methods
  6. Private Interface Methods
  7. The Diamond Problem
  8. Abstract Classes
  9. Interface vs Abstract Class
  10. Records (Java 16+)
  11. Record Patterns (Java 21)
  12. Sealed Classes (Java 17+)
  13. Sealed + Pattern Matching (Java 21)
  14. Certification Traps
  15. Common Mistakes
  16. Interview Questions
  17. Quick Revision Notes
  18. One-Page Cheat Sheet

1. Abstraction Overview

Abstraction means exposing what an object does while hiding how. Java offers several tools:

ToolUse When
InterfaceDefine a contract; multiple inheritance of type.
Abstract classShare common state + partial implementation.
RecordModel immutable data concisely.
Sealed classRestrict which classes can extend/implement.

2. Interfaces

An interface is a contract — a set of method signatures a class promises to implement using implements.

interface Drawable {
    void draw();          // public abstract by default
}

class Circle implements Drawable {
    @Override
    public void draw() { System.out.println("Drawing circle"); }
}
Drawable d = new Circle();   // program to the interface
d.draw();

Key Facts

FactDetail
Multiple inheritanceA class can implement many interfaces.
Interface extends interface(s)An interface can extend multiple interfaces.
Cannot be instantiatednew Drawable() is illegal (except anonymous classes).
Implicit public abstractMethods are public abstract unless default/static/private.
Reference typeYou can declare variables of an interface type.
interface A {}
interface B {}
interface C extends A, B {}      // interface multiple inheritance — OK

class D implements A, B {}       // class implements multiple — OK

3. Interface Members

Modern interfaces (Java 8+) can hold much more than abstract methods.

MemberModifierSince
Abstract methodimplicitly public abstract1.0
Constant fieldimplicitly public static final1.0
Default methoddefaultJava 8
Static methodstaticJava 8
Private methodprivateJava 9
Private static methodprivate staticJava 9
interface Config {
    int MAX = 100;                       // public static final (constant)

    void process();                      // public abstract

    default void log() {                 // Java 8
        System.out.println("Default log");
    }

    static Config create() {             // Java 8
        return new ConfigImpl();
    }

    private void helper() { }            // Java 9
    private static void util() { }       // Java 9
}

Constant Trap

interface Limits {
    int MAX = 100;          // this is public static final implicitly
    // MAX = 200;           // ERROR: cannot reassign a final
}

All interface fields are constants (public static final). You cannot have instance fields in an interface.


4. Default Methods

A default method provides a method body inside an interface, so implementing classes inherit it without writing it.

interface Vehicle {
    void start();                              // abstract

    default void honk() {                      // default with body
        System.out.println("Beep beep!");
    }
}

class Car implements Vehicle {
    @Override public void start() { System.out.println("Car started"); }
    // honk() inherited automatically
}

Why Default Methods Exist

They allow adding new methods to interfaces without breaking existing implementations (backward compatibility — e.g., List.sort(), Collection.stream()).

Rules

RuleDetail
Has a bodyMarked with default.
Can be overriddenImplementing classes may override.
publicAlways public (cannot be private/protected).
Not static/finalCannot combine default with static.
CallingInterfaceName.super.method() to invoke a specific default.

5. Static Interface Methods

Static methods belong to the interface itself and are not inherited by implementing classes.

interface MathOps {
    static int square(int x) { return x * x; }
}

// Call via interface name only:
int result = MathOps.square(5);   // 25

Trap: Not Inherited

class Calc implements MathOps {}

// Calc.square(5);     // ERROR: static interface method not inherited
MathOps.square(5);     // OK

Unlike static methods in classes, interface static methods are never inherited by implementing classes or subinterfaces.


6. Private Interface Methods

Since Java 9, interfaces can have private methods to share code among default/static methods without exposing it.

interface Logger {
    default void info(String msg)  { log("INFO", msg); }
    default void error(String msg) { log("ERROR", msg); }

    private void log(String level, String msg) {     // shared helper
        System.out.println("[" + level + "] " + msg);
    }
}
Private method typeCan be called by
privateDefault methods (instance context).
private staticBoth default and static methods.

Private interface methods must have a body and cannot be abstract.


7. The Diamond Problem

When a class inherits the same default method from two interfaces, it must override to resolve the conflict.

interface A { default void hello() { System.out.println("A"); } }
interface B { default void hello() { System.out.println("B"); } }

class C implements A, B {
    @Override
    public void hello() {
        A.super.hello();    // explicitly pick A's version
        // or B.super.hello();
    }
}
ConflictResolution
Two default methods, same signatureClass must override.
Use a parent's versionInterfaceName.super.method().
Class method vs interface defaultClass wins ("class always wins" rule).

"Class wins" rule: If a superclass provides a concrete method and an interface provides a default with the same signature, the class method takes precedence.


8. Abstract Classes

An abstract class is a partially implemented class that cannot be instantiated. It can hold state, constructors, and both abstract and concrete methods.

abstract class Animal {
    protected String name;                 // state allowed

    Animal(String name) { this.name = name; }   // constructor allowed

    abstract void sound();                 // must be implemented by subclass

    void describe() {                      // concrete method
        System.out.println(name + " says");
        sound();
    }
}

class Dog extends Animal {
    Dog(String name) { super(name); }
    @Override void sound() { System.out.println("Woof"); }
}
RuleDetail
Cannot instantiatenew Animal() is illegal.
Can have constructorsInvoked via super().
Can have instance fieldsUnlike interfaces.
Abstract methods have no bodySubclass must implement (or be abstract).
Single inheritanceA class extends only one abstract class.
abstract + finalIllegal.

9. Interface vs Abstract Class

FeatureInterfaceAbstract Class
Instantiable
Multiple inheritance✅ (implements many)❌ (extends one)
Instance fields❌ (only constants)
Constructors
Method bodiesdefault/static/private onlyAny (concrete)
Field typepublic static final onlyAny
Access modifiers on methodspublic (or private)Any
StateStateless (constants only)Can hold state
Use whenDefine a capability/contractShare code + state

Rule of thumb: Use an interface for a capability ("can do"); use an abstract class for an is-a relationship with shared state.


10. Records (Java 16+)

A record is a concise, immutable data carrier. The compiler auto-generates the constructor, accessors, equals(), hashCode(), and toString().

record Point(int x, int y) {}

This single line is equivalent to ~30 lines of boilerplate:

Point p = new Point(3, 4);
System.out.println(p.x());        // 3   (accessor is x(), NOT getX())
System.out.println(p.y());        // 4
System.out.println(p);            // Point[x=3, y=4]
System.out.println(p.equals(new Point(3, 4)));  // true

What the Compiler Generates

GeneratedDetail
Private final fieldsOne per component.
Canonical constructorTakes all components.
Accessorsx(), y() — named after components (no get).
equals() / hashCode()Based on all components.
toString()Point[x=3, y=4] form.

Compact Constructor (Validation)

record Range(int low, int high) {
    Range {                                  // compact canonical constructor
        if (low > high)
            throw new IllegalArgumentException("low > high");
        // fields assigned automatically AFTER this block
    }
}

Custom Methods & Static Members

record Circle(double radius) {
    static final double PI = 3.14159;        // static fields ALLOWED

    double area() { return PI * radius * radius; }   // extra method OK

    Circle {                                 // validation
        if (radius < 0) throw new IllegalArgumentException();
    }
}

Record Rules (Heavily Tested)

RuleDetail
Implicitly finalA record cannot be extended.
Extends java.lang.RecordSo it cannot extend any other class.
Can implement interfaces✅ Allowed.
Components are finalImmutable; no setters.
No instance fields beyond componentsOnly the declared components (static fields OK).
Can have static fields/methods
Can override accessors / equals / etc.✅ but rarely needed.
Can declare additional constructorsMust delegate to the canonical one via this(...).
// record cannot extend a class:
// record Bad(int x) extends SomeClass {}   // ERROR

record Named(String name) implements Comparable<Named> {   // interface OK
    public int compareTo(Named o) { return name.compareTo(o.name); }
}

11. Record Patterns (Java 21)

Java 21 lets you deconstruct records directly in instanceof and switch — a flagship feature.

record Point(int x, int y) {}

Object obj = new Point(3, 4);

// instanceof with record pattern
if (obj instanceof Point(int x, int y)) {
    System.out.println(x + ", " + y);   // 3, 4 — components bound directly
}

Nested Record Patterns

record Point(int x, int y) {}
record Line(Point start, Point end) {}

Object obj = new Line(new Point(0, 0), new Point(5, 5));

if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
    System.out.println("From " + x1 + "," + y1 + " to " + x2 + "," + y2);
}

In a switch (with var and guards)

static String describe(Object obj) {
    return switch (obj) {
        case Point(var x, var y) when x == y -> "diagonal point";
        case Point(var x, var y)             -> "point " + x + "," + y;
        default                               -> "not a point";
    };
}
FeatureDetail
DeconstructionExtract components into variables in one step.
NestingPatterns can be nested arbitrarily deep.
var in patternsType inference per component allowed.
GuardsCombine with when.

12. Sealed Classes (Java 17+)

A sealed class/interface restricts which classes may extend or implement it, using the permits clause. This gives you a known, closed set of subtypes.

sealed interface Shape permits Circle, Square, Triangle {}

final class Circle implements Shape {}
final class Square implements Shape {}
non-sealed class Triangle implements Shape {}

The Three Subtype Modifiers (Mandatory)

Every permitted subtype must be exactly one of:

ModifierMeaning
finalNo further subclasses.
sealedContinues the restriction (needs its own permits).
non-sealedReopens the hierarchy (anyone can extend).
sealed interface Animal permits Dog, Cat, Wild {}

final class Dog implements Animal {}
sealed class Cat implements Animal permits Kitten {}    // sealed continues
non-sealed class Wild implements Animal {}              // reopened
final class Kitten extends Cat {}

Sealed Rules (Critical)

RuleDetail
permits lists subtypesOnly listed types may extend/implement.
Subtypes must be accessibleIn the same module (or same package if unnamed module).
Each subtype declares a modifierfinal, sealed, or non-sealed.
permits can be omittedIf all subtypes are in the same source file.
Sealed + recordRecords are implicitly final, so they fit as permitted subtypes.
// permits omitted: all subtypes in the same file
sealed interface Expr {}
record Num(int v) implements Expr {}        // record is final -> valid
record Add(Expr l, Expr r) implements Expr {}

13. Sealed + Pattern Matching (Java 21)

Sealed types + pattern matching switch enable exhaustive checking — the compiler knows all possible subtypes, so no default is needed.

sealed interface Shape permits Circle, Square, Triangle {}
record Circle(double radius) implements Shape {}
record Square(double side) implements Shape {}
record Triangle(double base, double height) implements Shape {}

static double area(Shape shape) {
    return switch (shape) {                  // NO default needed!
        case Circle c   -> Math.PI * c.radius() * c.radius();
        case Square s   -> s.side() * s.side();
        case Triangle t -> 0.5 * t.base() * t.height();
    };
}

Combined with Record Deconstruction

static double area(Shape shape) {
    return switch (shape) {
        case Circle(double r)        -> Math.PI * r * r;
        case Square(double s)        -> s * s;
        case Triangle(double b, double h) -> 0.5 * b * h;
    };
}

Why This Matters

BenefitDetail
ExhaustivenessCompiler verifies all subtypes are handled.
No defaultAdding a new permitted subtype causes a compile error until handled.
Safe refactoringThe compiler flags every switch that must be updated.

This is the "algebraic data type" pattern — sealed types + records + pattern matching is the headline modeling feature of modern Java.


14. Certification Traps

#Trap
1Interface fields are implicitly public static final — no instance fields.
2Interface methods are implicitly public abstract (unless default/static/private).
3Static interface methods are not inherited — call via interface name.
4Diamond conflict on default methods must be resolved by overriding.
5"Class wins": a superclass concrete method beats an interface default.
6Use InterfaceName.super.method() to call a specific default.
7Records are implicitly final and extend Record — cannot extend a class.
8Record accessor is x(), not getX().
9Compact constructor has no parameter list and assigns fields implicitly.
10Additional record constructors must delegate to the canonical one (this(...)).
11Records can implement interfaces and have static fields, but no extra instance fields.
12Every sealed subtype must be final, sealed, or non-sealed.
13permits can be omitted only if subtypes are in the same file.
14Sealed + pattern switch is exhaustive — no default required.
15private interface methods must have a body (cannot be abstract).

15. Common Mistakes

MistakeFix
Adding instance fields to an interfaceOnly constants allowed; use an abstract class.
Calling a static interface method via a classCall via the interface name.
Forgetting to resolve a diamond conflictOverride and pick with Interface.super.method().
Using getX() on a recordUse the component accessor x().
Trying to extend a recordRecords are final; use composition or interfaces.
Forgetting a subtype modifier in a sealed hierarchyMark each final/sealed/non-sealed.
Adding default to make a record mutableRecords are immutable by design.
Adding default keyword and a body that's staticdefault and static cannot combine.

16. Interview Questions

Q1. What is the difference between an interface and an abstract class? An interface defines a contract (no state, multiple inheritance, only constants and default/static/private method bodies). An abstract class can hold state, constructors, and concrete methods but supports single inheritance.

Q2. Why were default methods introduced? To add new methods to existing interfaces without breaking implementing classes (backward compatibility), e.g., Collection.stream().

Q3. Are static interface methods inherited? No — they belong to the interface and must be called using the interface name.

Q4. How do you resolve the diamond problem with default methods? Override the conflicting method and explicitly call the desired version with InterfaceName.super.method().

Q5. What is the "class wins" rule? If a superclass provides a concrete method and an interface provides a default with the same signature, the superclass method is used.

Q6. What is a record and what does it generate? An immutable data carrier; the compiler generates final fields, a canonical constructor, accessors, equals(), hashCode(), and toString().

Q7. Can a record extend a class or be extended? No to both — records implicitly extend Record and are implicitly final. They can implement interfaces.

Q8. What is a compact constructor? A canonical constructor without a parameter list, used for validation/normalization; field assignment happens automatically after the block.

Q9. What is a sealed class? A class/interface that restricts which types can extend/implement it via the permits clause.

Q10. What modifiers must permitted subtypes use? Each must be final, sealed, or non-sealed.

Q11. How do sealed types improve switch? The compiler knows all permitted subtypes, enabling exhaustive switch without a default and flagging unhandled cases at compile time.

Q12. What are record patterns (Java 21)? A way to deconstruct a record's components directly in instanceof/switch, with support for nesting and guards.


17. Quick Revision Notes

  • Interface fields = public static final; methods = public abstract by default.
  • Java 8: default + static interface methods; Java 9: private + private static.
  • Static interface methods are not inherited; call via interface name.
  • Diamond conflict → must override; use Interface.super.method().
  • "Class wins" over interface default.
  • Abstract class: state + constructors + concrete methods; single inheritance; can't instantiate.
  • Use interface for capability, abstract class for shared state/is-a.
  • Records: immutable, implicitly final, extend Record, accessors x() not getX().
  • Compact constructor: no params, validates, auto-assigns fields.
  • Records can implement interfaces + have static members, but no extra instance fields.
  • Record patterns (21): deconstruct in instanceof/switch, nestable, support var + guards.
  • Sealed: permits lists subtypes; each subtype is final/sealed/non-sealed.
  • permits optional if subtypes share the file.
  • Sealed + pattern switch = exhaustive, no default needed.

18. One-Page Cheat Sheet

======== INTERFACES, ABSTRACT, RECORDS & SEALED CHEAT SHEET ========

INTERFACE
  fields: public static final (constants only, no instance state)
  methods: public abstract (default)
  default void m(){...}   // Java 8, instance body, overridable
  static  void m(){...}   // Java 8, NOT inherited, call Iface.m()
  private void m(){...}   // Java 9, helper for defaults
  private static m(){...} // Java 9
  class implements many interfaces ; interface extends many interfaces

DIAMOND PROBLEM
  two default methods same sig -> class MUST override
  pick one: InterfaceName.super.method()
  CLASS WINS over interface default

ABSTRACT CLASS
  cannot instantiate ; has state + constructors + concrete + abstract
  single inheritance ; abstract+final = ILLEGAL
  use: shared state/is-a   (interface: capability/contract)

RECORD (16+)  record Point(int x, int y){}
  immutable, implicitly FINAL, extends Record (no class extend)
  auto: fields, canonical ctor, x()/y() accessors, equals, hashCode, toString
  accessor is x() NOT getX()
  compact ctor:  Point { if(...) throw ...; }   // no params, auto-assign
  can: implement interfaces, static fields/methods, extra methods
  extra constructors must delegate this(...)

RECORD PATTERNS (21)
  if (o instanceof Point(int x, int y)) {...}
  nested: instanceof Line(Point(int x1,int y1), Point(int x2,int y2))
  switch: case Point(var x, var y) when x==y -> ...

SEALED (17+)
  sealed interface Shape permits Circle, Square {}
  each subtype: final | sealed (own permits) | non-sealed
  permits optional if all subtypes in SAME FILE
  records fit (they are final)

SEALED + SWITCH (21)
  switch(shape){ case Circle c->...; case Square s->...; }  // NO default
  exhaustive: compiler verifies all permitted subtypes handled
====================================================================

End of 06 - Interfaces, Abstract Classes, Records, and Sealed Classes.