3.4 Abstract Classes and Interfaces

Key Takeaways

  • Abstract classes declare shared state and partial implementations with constructors, but cannot be directly instantiated.
  • Interfaces define contracts supporting multiple inheritance of type, containing public abstract methods, default methods, static methods, and private helper methods.
  • Default method conflicts from multiple interface inheritance must be explicitly resolved in the implementing class using the InterfaceName.super.method() syntax.
  • Under the class-always-wins rule, an inherited concrete superclass method always takes precedence over an interface default method of the same signature.
Last updated: September 2026

Abstract Classes and Interfaces

In Java SE 21, abstraction is realized through two distinct constructs: abstract classes and interfaces. While both prohibit direct instantiation and define contracts for subclasses, they serve different architectural roles and follow distinct inheritance and member accessibility rules.


Abstract Classes vs. Interfaces: Architectural Comparison

DimensionAbstract ClassInterface
Inheritance ModelSingle inheritance (class A extends B)Multiple inheritance of type (class A implements B, C)
Instance State / FieldsCan declare mutable instance fields (private int x;)No instance state; variables are implicitly public static final
ConstructorsSupported (invoked via super(...) during subclass instantiation)Prohibited (interfaces cannot declare constructors)
Method Types SupportedAbstract, concrete instance, static, final, privateAbstract, default, static, private, private static
Default Method VisibilityPackage-private by default (any modifier allowed)Implicitly public (unless explicitly declared private)
Primary Design PurposeShared identity, base state, and partial implementationCapability contracts and decoupled API specifications

Abstract Class Mechanics and Rules

An abstract class is declared with the abstract keyword and serves as an incomplete base class.

public abstract class AbstractTaskProcessor {
    private final String processorName;
    protected int processedCount = 0;

    // Abstract classes support constructors
    public AbstractTaskProcessor(String processorName) {
        this.processorName = processorName;
    }

    public String getProcessorName() { return processorName; }

    // Abstract method: declares contract without body
    public abstract void processPayload(String payload);

    // Concrete template method
    public void execute(String payload) {
        System.out.println("Initializing " + processorName);
        processPayload(payload);
        processedCount++;
    }
}

Critical Rules for Abstract Classes and Methods

  1. Instantiation Prohibition: You cannot instantiate an abstract class directly using new AbstractClass().
  2. Abstract Method Body: An abstract method consists of a method signature terminated by a semicolon (;). It cannot have a method body enclosed in braces {}.
  3. Class Declaration Requirement: If a class contains at least one abstract method (declared or inherited without implementation), the class itself must be declared abstract.
  4. Subclass Obligations: The first concrete (non-abstract) subclass in an inheritance chain must provide concrete method bodies for all inherited abstract methods. Intermediate abstract subclasses may implement some, all, or none of the inherited abstract methods, and may introduce new abstract methods.
  5. Illegal Modifier Combinations: Abstract methods cannot be declared:
    • abstract final: final prevents overriding, while abstract demands overriding.
    • abstract static: static methods cannot be overridden dynamically.
    • abstract private: private methods are invisible to subclasses and cannot be implemented.
    • abstract synchronized or abstract native: Synchronization and native implementations apply to concrete execution bodies, not abstract signatures.

Modern Interface Architecture in Java SE 21

Since Java 8 and Java 9, interfaces support rich contracts containing five distinct categories of methods:

public interface MessageService {
    // 1. Constant Field: implicitly public static final
    int MAX_RETRIES = 3;

    // 2. Abstract Method: implicitly public abstract
    void sendMessage(String recipient, String message);

    // 3. Default Method (Java 8+): public instance method with default implementation
    default void sendWithRetry(String recipient, String message) {
        for (int i = 0; i < MAX_RETRIES; i++) {
            try {
                logAttempt(recipient, i + 1);
                sendMessage(recipient, message);
                return;
            } catch (Exception e) {
                logFailure(recipient, e);
            }
        }
    }

    // 4. Static Method (Java 8+): utility method attached to interface namespace
    static MessageService createConsoleService() {
        return (recipient, msg) -> System.out.println("To " + recipient + ": " + msg);
    }

    // 5. Private Instance Method (Java 9+): helper method shared between default methods
    private void logAttempt(String recipient, int attempt) {
        System.out.println("[ATTEMPT " + attempt + "] Sending to " + recipient);
    }

    // 6. Private Static Method (Java 9+): helper method shared between static methods
    private static void logFailure(String recipient, Exception e) {
        System.err.println("[FAILED] " + recipient + ": " + e.getMessage());
    }
}

Interface Member Rules and Visibility

  • Interface Fields: All fields declared in an interface are implicitly public static final. They must be initialized at declaration time. Marking them private, protected, or non-final causes a compile-time error.
  • Default Methods: Marked with the default keyword and provide a full method body. They are implicitly public. Implementing classes inherit default methods and can choose to use them directly or override them. Default methods cannot be marked static, final, or abstract.
  • Static Methods in Interfaces: Belong exclusively to the interface. Interface static methods are NOT inherited by implementing classes or subinterfaces. They must be invoked using the explicit syntax: InterfaceName.staticMethodName().
  • Private Methods: Introduced in Java 9 to encapsulate helper code without exposing public default or static APIs. Can be private (instance helper for default methods) or private static (static helper for static/default methods).

Resolving Multiple Inheritance Conflicts (The Diamond Problem)

Because a Java class can implement multiple interfaces, conflicting default methods can introduce ambiguity.

interface TransmitterA {
    default void transmit() {
        System.out.println("Transmitting via Channel A");
    }
}

interface TransmitterB {
    default void transmit() {
        System.out.println("Transmitting via Channel B");
    }
}

// COMPILE ERROR if transmit() is not overridden!
public class RadioStation implements TransmitterA, TransmitterB {
    // Implementing class MUST resolve the conflict explicitly
    @Override
    public void transmit() {
        // Option 1: Completely custom logic
        System.out.println("Custom Station Transmission");
        
        // Option 2: Delegate to a specific interface default method using InterfaceName.super
        TransmitterA.super.transmit();
    }
}

Priority Rules for Default Method Resolution

  1. The "Class Always Wins" Rule: If a superclass provides a concrete implementation of a method, and an implemented interface provides a default method with the exact same signature, the superclass implementation always takes precedence. The interface default method is completely ignored and no conflict occurs.
class BaseLogger {
    public void log(String msg) {
        System.out.println("BaseLogger: " + msg);
    }
}

interface InterfaceLogger {
    default void log(String msg) {
        System.out.println("InterfaceLogger: " + msg);
    }
}

class AppLogger extends BaseLogger implements InterfaceLogger {
    // No compile error! BaseLogger.log() wins automatically.
}
  1. The "Sub-Interface Wins" Rule: If Interface B extends Interface A and overrides A's default method, an implementing class that implements both A and B will automatically inherit B's more specific implementation.
  2. Explicit Conflict Resolution: If two unrelated interfaces provide default methods with the same signature, the implementing class must override the method, or a compile-time error occurs. Within the override, the developer may delegate using InterfaceName.super.methodName().

Common 1Z0-830 Exam Traps

  • Calling Interface Static Methods on Implementing Classes: Calling AppLogger.createConsoleService() or myInstance.createConsoleService() where createConsoleService is a static method in MessageService causes a compile error. You MUST write MessageService.createConsoleService().
  • Default Method Super Syntax: The syntax to delegate to an interface default method is strictly InterfaceName.super.method(). Writing super.method() or InterfaceName.method() fails compilation.
  • Uninitialized Interface Constants: Declaring int TIMEOUT; inside an interface causes a compile-time error because interface fields are implicitly final and must be initialized.
  • Abstract Class with Zero Abstract Methods: An abstract class does not need to have any abstract methods; it is perfectly valid to create an abstract class solely to prevent direct instantiation.
Loading diagram...
Multiple Interface Default Method Conflict Resolution
Test Your Knowledge

Consider the following interface definitions and class declaration:

interface Reader {
    default String read() { return "Reading text"; }
}

interface Scanner {
    default String read() { return "Scanning barcode"; }
}

class SmartDevice implements Reader, Scanner {
    // Line 1
}
Which code at Line 1 correctly resolves the default method conflict?

A
B
C
D
Test Your Knowledge

Examine the following interface and implementing class:

interface Validator {
    static boolean isValid(String s) {
        return s != null && !s.isBlank();
    }
}

public class FormValidator implements Validator {
    public void check(String data) {
        // Line X
    }
}
Which statement at Line X is valid to invoke isValid?

A
B
C
D
Test Your Knowledge

Consider the following class and interface definition:

class BaseService {
    public String process() { return "BaseService"; }
}

interface ServiceContract {
    default String process() { return "ServiceContract"; }
}

class OrderService extends BaseService implements ServiceContract {}
What is the result when executing new OrderService().process()?

A
B
C
D
Test Your Knowledge

Which of the following method declarations is ILLEGAL inside a top-level interface in Java SE 21?

A
B
C
D