Definition
The choice between interface and abstract class depends on four remaining differences after Java 8.
- Choose interface when: defining a capability contract that unrelated classes can implement (Auditable, Comparable, Serializable), you need multiple inheritance of type, or the contract has no mutable state.
- Choose abstract class when: sharing mutable state (fields) and constructors among a family of related classes (
SavingsAccountandCurrentAccountsharebalance,accountId), or you need non-public methods (protectedhelper methods). - Why not interchangeable: (1) interfaces cannot have constructors, (2) interfaces cannot have instance fields, (3) interface methods are implicitly
public(no protected), (4) a class can extend only one abstract class. - Modern guideline: default to interface. Use abstract class only when you need constructors or shared mutable instance fields.
Interface is like a banking license at National Bank of India: any institution (bank, fintech, cooperative) can hold it. Multiple licenses allowed. Abstract class is like a bank template with pre-filled forms and a vault (state): only branches of this bank can use it. You can only belong to one bank (single inheritance) but hold many licenses (multiple interfaces). Java 8 gave licenses the ability to include instructions (default methods), but licenses still cannot have a vault (state) or a reception desk (constructor).
Understanding the Concepts
When do you choose interface vs abstract class?
The decision is driven by four remaining differences after Java 8.
What are the four remaining differences?
// Difference 1: CONSTRUCTORS
public abstract class Account {
protected Account(String accountId, java.math.BigDecimal balance) {
// Constructor initializes shared state for all subclasses.
}
}
// Interface: no constructor. Cannot initialize state on creation.
// Difference 2: INSTANCE FIELDS
public abstract class Account {
protected java.math.BigDecimal balance; // mutable instance field
}
public interface Auditable {
java.math.BigDecimal MAX = java.math.BigDecimal.TEN; // public static final only
// BigDecimal balance; -> compile error: no instance fields
}
// Difference 3: ACCESS MODIFIERS
public abstract class Account {
protected void internalValidate() { } // protected: family only
}
public interface Auditable {
void generateReport(); // implicitly public
// protected void internal() { } -> compile error
}
// Difference 4: SINGLE vs MULTIPLE INHERITANCE
class SavingsAccount extends Account implements Auditable, Taxable { }
// class X extends Account, AnotherClass { } -> compile error
What is the decision flowchart?
What does this look like in a real banking system?
// Account: abstract class (has state, constructor, template method)
public abstract class Account {
protected java.math.BigDecimal balance;
private final String accountId;
protected Account(String id, java.math.BigDecimal bal) {
this.accountId = id; this.balance = bal;
}
public abstract java.math.BigDecimal calculateInterest();
}
// Auditable: interface (capability, any class can have it)
public interface Auditable {
java.util.List<String> generateAuditReport();
}
// Taxable: interface (capability, any class can have it)
public interface Taxable {
java.math.BigDecimal calculateTax();
}
// SavingsAccount: extends abstract class, implements interfaces
public class SavingsAccount extends Account implements Auditable, Taxable {
// Account: shared state (balance, accountId) + template method
// Auditable + Taxable: capabilities from interfaces
}
What does Spring use in practice?
// Spring uses interfaces for contracts:
public interface JpaRepository<T, ID> { } // any entity can implement
public interface Serializable { } // any class can implement
// Spring uses abstract classes for shared state and template methods:
public abstract class AbstractController {
private WebApplicationContext context; // state: interface cannot have this
protected abstract ModelAndView handleRequest();
}
How do interface and abstract class compare?
| Aspect | Interface | Abstract Class |
|--------|----------|----------------|
| Instance fields | No (constants only) | Yes |
| Constructors | No | Yes |
| Multiple inheritance | Yes | No |
| Access modifiers | public only | Any |
| Default methods (Java 8) | Yes | N/A (always had bodies) |
| Use case | Capability contract | Family with shared state |
What are common mistakes?
The most common mistake is using an abstract class for a stateless contract, wasting the single inheritance slot.
What should a senior engineer know?
- In Spring Boot, services implement interfaces (loose coupling, multiple implementations). JPA entity base classes are abstract classes (shared @Id, @CreatedDate fields).
- The choice is driven by state: if you need shared mutable state with initialization, abstract class. If you need a contract with optional default behavior, interface.
- Sealed interfaces (Java 17) combine interface flexibility with controlled hierarchy.
Visual Overview
DECISION FLOWCHART
──────────────────────────────────────────
Need instance fields? ──Yes──> ABSTRACT CLASS
│
No
│
Need constructor? ──Yes──> ABSTRACT CLASS
│
No
│
Multiple unrelated classes? ──Yes──> INTERFACE
│
No
│
Family IS-A hierarchy? ──Yes──> ABSTRACT CLASS
│
No
│
Default choice ──────────────> INTERFACE
Key Takeaway
Choose interface when defining a capability that unrelated classes can implement (Auditable, Comparable, Serializable) and you need multiple inheritance of type. Choose abstract class when sharing mutable state (balance field, auditLog list) and constructors among a family of related classes (SavingsAccount IS-A Account). Java 8 default methods narrowed the gap by adding method bodies to interfaces, but they are still not interchangeable.
The four remaining differences: interfaces cannot have instance fields (only public static final constants), cannot have constructors (no state initialization), default methods are implicitly public (no protected access for family-only methods), and a class can extend only one abstract class but implement unlimited interfaces.
Remember one sentence: default to interface for contracts and capabilities, and use abstract class only when you genuinely need constructors or shared mutable instance fields.
---