Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • About
  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

ยฉ 2026 Chaturmind. All rights reserved.

๐Ÿ‘ฅ10,046visitors

Built for engineers who want to go deep.


โ† Java Core Fundamentals

Object-Oriented Programming

  • Classes and Objects
  • Inheritance and Polymorphism
  • Interfaces and Abstract Classes

Collections Framework

  • List, Set, and Map
  • Generics
  • Collections Framework Recap
  • HashMap Deep Dive
  • TreeMap & LinkedHashMap
  • Iterators & Modification Semantics

Exceptions & Best Practices

  • Exception Handling
  • equals() and hashCode()
  • String Manipulation

JVM Internals & Memory Management

  • JVM Memory Areas
  • Garbage Collection Fundamentals
  • Modern Garbage Collectors
  • Memory Leaks in Java
  • GC Tuning & Diagnostics
Chaturmind
โ† Java Core Fundamentals

Object-Oriented Programming

  • Classes and Objects
  • Inheritance and Polymorphism
  • Interfaces and Abstract Classes

Collections Framework

  • List, Set, and Map
  • Generics
  • Collections Framework Recap
  • HashMap Deep Dive
  • TreeMap & LinkedHashMap
  • Iterators & Modification Semantics

Exceptions & Best Practices

  • Exception Handling
  • equals() and hashCode()
  • String Manipulation

JVM Internals & Memory Management

  • JVM Memory Areas
  • Garbage Collection Fundamentals
  • Modern Garbage Collectors
  • Memory Leaks in Java
  • GC Tuning & Diagnostics
HomeLearnJavaJava Core FundamentalsObject-Oriented Programming
โœ“ FreeIntermediateยท 6 min read

Interfaces and Abstract Classes

Design flexible contracts with interfaces and share logic with abstract classes.

Published September 21, 2026


Interfaces and Abstract Classes

Both interfaces and abstract classes let you write code against a general type while the specific behaviour comes from implementations you plug in later. They solve different problems, though:

  • An interface describes what something can do, a capability or contract: Comparable, Runnable, PaymentGateway. It says nothing about how.
  • An abstract class is a partially built class: shared state and shared code for a family of closely related classes, with some steps left for subclasses to fill in.

Choosing well matters for how easily a codebase can grow, and it's a staple interview question.

Advertisement

Interfaces: contracts

public interface PaymentGateway {
    PaymentResult charge(Money amount, String customerId);   // implicitly public abstract

    default boolean supportsRefunds() {                       // default method (Java 8+): optional to override
        return false;
    }

    static PaymentGateway noop() {                            // static helper (Java 8+)
        return (amount, customer) -> PaymentResult.approved("noop");
    }
}

public class StripeGateway implements PaymentGateway {
    @Override
    public PaymentResult charge(Money amount, String customerId) { /* call Stripe */ }

    @Override
    public boolean supportsRefunds() { return true; }
}

What an interface can contain:

  • Abstract methods: the contract. They're implicitly public.
  • Default methods (Java 8+): a method with a body that implementations inherit unless they override it. They were added so interfaces could evolve (for example List.sort) without breaking every existing implementation.
  • Static methods (Java 8+): helpers that belong to the interface.
  • Private methods (Java 9+): shared code for default methods.
  • Constants: fields are implicitly public static final.

What it can't have: instance fields (per-object state) or constructors.

A class can implement many interfaces (class Task implements Runnable, Comparable<Task>, Serializable). This is how Java provides multiple inheritance of type without multiple inheritance of state.

Abstract classes: shared implementation

public abstract class ReportGenerator {
    private final Clock clock;                          // shared state
    protected ReportGenerator(Clock clock) { this.clock = clock; }

    // The fixed algorithm โ€” final so subclasses can't break the sequence
    public final Report generate(ReportRequest request) {
        List<Row> rows = fetchData(request);            // step supplied by subclasses
        List<Row> filtered = applyFilters(rows, request);
        return new Report(render(filtered), clock.instant());
    }

    protected abstract List<Row> fetchData(ReportRequest request);     // must implement
    protected abstract String render(List<Row> rows);                  // must implement

    protected List<Row> applyFilters(List<Row> rows, ReportRequest r) { // optional hook with a default
        return rows;
    }
}

public class SalesCsvReport extends ReportGenerator {
    public SalesCsvReport(Clock clock) { super(clock); }
    @Override protected List<Row> fetchData(ReportRequest r) { /* query sales */ }
    @Override protected String render(List<Row> rows) { /* build CSV */ }
}

What an abstract class offers that an interface doesn't:

  • Instance fields and constructors: real shared state and initialization.
  • Any access level: protected hooks, and private helpers used by subclasses indirectly.
  • final methods that fix an algorithm's structure while delegating specific steps. That's the Template Method pattern shown above.

It can't be instantiated, and a class can extend only one abstract class.

Side by side

InterfaceAbstract class
PurposeA capability / contractPartial implementation for related classes
Instance stateโŒ (constants only)โœ…
ConstructorsโŒโœ…
Method bodiesdefault, static, privateAny
Access modifiers of memberspublic (private helpers since Java 9)Any
A class can haveManyOne
Relationship expressed"can do" (Comparable)"is a kind of" (ReportGenerator)

How to choose

  • Start with an interface when defining what collaborators need from each other: repositories, gateways, notifiers, strategies. It's the most flexible option: any class can implement it, including classes that already extend something else, and it's trivial to mock in tests.
  • Add an abstract class when several implementations genuinely share state or a fixed algorithm. A common pattern is both: an interface as the public type, plus an abstract base class that implements it and provides the shared parts (List + AbstractList in the JDK). Callers depend on the interface, and implementers extend the base class for convenience.
  • Don't use an abstract class just to share a few utility methods. Composition (a helper object) or a static utility is often cleaner than forcing an inheritance hierarchy.

Functional interfaces

An interface with exactly one abstract method is a functional interface, and it can be implemented with a lambda:

@FunctionalInterface
interface DiscountPolicy { Money apply(Money price); }

DiscountPolicy tenPercentOff = price -> price.multiply(0.9);

@FunctionalInterface is optional, but makes the compiler enforce the single-abstract-method rule. Runnable, Comparator, Function and Predicate are all functional interfaces (see Lambda Expressions).

The default-method diamond

If a class implements two interfaces that both provide a default method with the same signature, the compiler forces the class to resolve the conflict explicitly:

interface Printer { default String describe() { return "printer"; } }
interface Scanner { default String describe() { return "scanner"; } }

class AllInOne implements Printer, Scanner {
    @Override
    public String describe() {
        return Printer.super.describe() + "+" + Scanner.super.describe();   // choose or combine explicitly
    }
}

Rules: a method inherited from a class wins over an interface default; a more specific interface wins over a less specific one; any remaining ambiguity must be resolved by overriding.

Follow-up questions this topic invites โ€” and their answers

Q: Now that interfaces have default methods, why do abstract classes still exist? A: Interfaces still can't hold instance state or constructors, and their members are public. Abstract classes remain the tool for sharing state and protected implementation, and for enforcing a fixed algorithm with final template methods. Default methods mainly exist to evolve interfaces without breaking implementers.

Q: Can an abstract class have a constructor if it can't be instantiated? A: Yes. It runs when a concrete subclass is instantiated (through super(...)), and initializes the shared state defined in the abstract class.

Q: Can an interface have fields? A: Only constants: every field is implicitly public static final. Using interfaces just to hold constants (the "constant interface" pattern) is discouraged. Put constants in the class or enum they belong to.

Q: Why program to interfaces? A: Code that depends on PaymentGateway rather than StripeGateway can switch implementations, use fakes or mocks in tests, and apply patterns like Strategy or Decorator without changing callers. It's also what makes dependency injection frameworks like Spring effective.

Q: What happens if a class implements two interfaces with the same default method? A: Compilation fails until the class overrides the method. Inside the override it can call a specific version with InterfaceName.super.method(), or provide completely new behaviour.

Advertisement

Previous

Inheritance and Polymorphism

Next

List, Set, and Map

AI Tutor

Lesson: Interfaces and Abstract Classes

Quick actions

AI responses can be inaccurate. Verify critical information.