Stage 2: Object-oriented programming, lesson 8 of 15

Interface vs abstract class: when should I use which?

Intermediate3 min read@since 9Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

Since Java 8, interfaces can have default and static methods, so the two look alike. Decide by what you need.

Choose an interface when

  • You're defining a capability or contract: Comparable, Runnable, PaymentGateway, NotificationSender.
  • Unrelated classes should share it (a Course and a User can both be Exportable).
  • You want to stay flexible: a class can implement many interfaces but extend only one class.
  • You want easy swapping and mocking (Spring injects interfaces; tests pass fakes).
  • You want lambdas: only interfaces can be functional.

Choose an abstract class when

  • Related classes share state (fields) and real code.
  • You need constructors, protected members or controlled initialisation.
  • You want a fixed algorithm with steps that subclasses fill in (the Template Method pattern).

Often both: an interface for the contract plus an abstract base class that implements the boring parts. The JDK does this with List and AbstractList.

A quick test: if you'd describe it with "can …" or "is able to …", make an interface. If you'd say "is a kind of … and shares …", consider an abstract class.

Side by side

InterfaceAbstract class
PurposeA contract: what a type can doA partial implementation: shared state and code
Instance fieldsNo (only constants)Yes
ConstructorsNoYes (called via super(...))
Methodsabstract, default, static, private (Java 9)Any: abstract and concrete
Access modifiersMethods are public (or private helpers)Any: public, protected, package-private, private
InheritanceA class can implement manyA class can extend only one
LambdasYes, if it has one abstract methodNo
Adding a method laterAdd a default method: nothing breaksAdd a concrete method: nothing breaks
Typical examplesComparable, List, RunnableAbstractList, HttpServlet, InputStream

Example

Java
// Interface: a capability; any class can have it
public interface PaymentGateway {
    PaymentResult charge(String orderId, long amountPaise);

    default boolean supportsUpi() { return false; }          // Java 8: evolve without breaking implementations
}

public class RazorpayGateway implements PaymentGateway {
    public PaymentResult charge(String orderId, long amountPaise) { /* call Razorpay */ return PaymentResult.ok(); }
    @Override public boolean supportsUpi() { return true; }
}

// Abstract class: shared state + a fixed algorithm (Template Method)
public abstract class ReportGenerator {
    private final Clock clock;                                // shared state
    protected ReportGenerator(Clock clock) { this.clock = clock; }

    public final String generate() {                          // the steps can't be reordered
        return header() + "\n" + body() + "\nGenerated " + LocalDate.now(clock);
    }
    protected String header() { return "JavaAtlas report"; }  // a default step
    protected abstract String body();                         // subclasses must fill this in
}

public class SalesReport extends ReportGenerator {
    public SalesReport(Clock clock) { super(clock); }
    @Override protected String body() { return "Revenue: ₹29,980"; }
}

Common mistake

Creating an abstract "BaseService" just to share a few helper methods. Every service is then stuck with one parent forever; use composition or a small helper class instead.

Under the hood

Default methods exist so libraries can evolve: Java 8 added stream() to Collection and sort() to List without breaking every implementation ever written. They can't hold state, though, so if you catch yourself wishing an interface had a field, you want an abstract class (or composition). Since Java 17, sealed interfaces and classes can also restrict who implements them, which is great for fixed sets of types such as payment results.

Check yourself

Which one can declare instance fields?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of OOP in practice.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.