Back to Abstraction & Interfaces
Q2Question 2 of 4

Can an abstract class extend another class and implement interfaces?

Key Concepts
  • Yes: an abstract class can extend one class (abstract or concrete) and implement multiple interfaces simultaneously
  • Being abstract, it can leave interface methods unimplemented for concrete subclasses to handle
  • This creates a layered hierarchy where each layer adds more specificity
  • A concrete (non-abstract) subclass at the bottom must implement all remaining abstract methods
  • This pattern is common in banking frameworks where a base entity is extended by domain-specific abstract classes
  • Each layer can provide partial implementations, reducing duplication across concrete subclasses

Definition

Yes: an abstract class can extend one class (abstract or concrete) and implement multiple interfaces simultaneously. It can leave interface methods unimplemented for concrete subclasses. The concrete child at the bottom must implement all remaining abstract methods.

An abstract class can simultaneously extend one other class and implement multiple interfaces.

  • Extends one class: abstract class InterestBearingAccount extends Account inherits state and behavior from Account.
  • Implements multiple interfaces: implements Auditable, Taxable declares capabilities.
  • Can leave methods unimplemented: being abstract, it can defer interface method implementations to concrete subclasses.
  • Concrete subclass must finish: a non-abstract class at the bottom of the chain must implement all remaining abstract methods from the parent chain and all unimplemented interface methods.
  • Creates layered hierarchy: each layer adds more specificity. Account (base state) -> InterestBearingAccount (adds interest + declares Auditable) -> SavingsAccount (provides all implementations).

Think of it as a training manual at National Bank of India. Account (abstract class) is the master manual with common procedures (deposit, withdraw). InterestBearingAccount (abstract class) extends Account and adds interest-related procedures but leaves calculateInterest() for specific account types to define. It also implements Auditable and Taxable, declaring those capabilities. SavingsAccount (concrete class) extends InterestBearingAccount and provides all the missing pieces.

Understanding the Concepts

Can an abstract class extend another class and implement interfaces?

Yes. The key insight: an abstract class is allowed to have unfinished business. It can declare that it implements an interface without providing the method body.

How does a layered hierarchy work?

JAVA
package com.bank.core;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

// Layer 1: base abstract class with state
public abstract class Account {
    protected String accountId;
    protected BigDecimal balance;

    protected Account(String id, BigDecimal bal) {
        this.accountId = id;
        this.balance = bal;
    }

    public void deposit(BigDecimal amount) { balance = balance.add(amount); }
    public abstract String getAccountType();
}

// Layer 2: abstract class extends Account AND implements 2 interfaces
public abstract class InterestBearingAccount extends Account implements Auditable, Taxable {
    protected BigDecimal annualRate;

    protected InterestBearingAccount(String id, BigDecimal bal, BigDecimal rate) {
        super(id, bal);
        this.annualRate = rate;
    }

    public BigDecimal calculateMonthlyInterest() {
        return balance.multiply(annualRate).divide(BigDecimal.valueOf(12), 2, RoundingMode.HALF_UP);
    }

    // getAccountType() from Account: still abstract, passed to concrete subclass.
    // Auditable.generateAuditReport(): still abstract, passed to concrete subclass.
    // Taxable.calculateTax(): still abstract, passed to concrete subclass.
    // This class must be abstract because it has unimplemented methods.
}

// Layer 3: concrete class implements ALL remaining abstract methods
public class SavingsAccount extends InterestBearingAccount {
    public SavingsAccount(String id, BigDecimal bal, BigDecimal rate) {
        super(id, bal, rate);
    }

    @Override
    public String getAccountType() { return "SAVINGS"; }

    @Override
    public List<String> generateAuditReport() {
        return List.of("Account: " + accountId, "Balance: Rs." + balance);
    }

    @Override
    public BigDecimal calculateTax() {
        BigDecimal yearlyInterest = calculateMonthlyInterest().multiply(BigDecimal.valueOf(12));
        return yearlyInterest.multiply(new BigDecimal("0.30")); // 30% tax on interest
    }
}

What methods are abstract at each layer?

| Layer | Class | Abstract Methods | Concrete Methods |
|-------|-------|-----------------|------------------|
| 1 | Account | getAccountType() | deposit() |
| 2 | InterestBearingAccount | getAccountType(), generateAuditReport(), calculateTax() | calculateMonthlyInterest() |
| 3 | SavingsAccount | None (all implemented) | Everything above + overrides |

Can the middle layer partially implement interface methods?

Yes. The abstract class can implement some interface methods and leave others for the concrete subclass.

JAVA
public abstract class InterestBearingAccount extends Account implements Auditable, Taxable {
    // Implements Auditable.generateAuditReport() here:
    @Override
    public List<String> generateAuditReport() {
        return List.of("Account: " + accountId, "Type: " + getAccountType());
    }

    // Leaves Taxable.calculateTax() abstract: concrete subclass must implement.
}
// Now SavingsAccount only needs: getAccountType() + calculateTax()

When is this pattern useful?

This pattern is useful when multiple concrete classes share intermediate behavior but differ in specifics.

JAVA
// FixedDepositAccount also extends InterestBearingAccount:
public class FixedDepositAccount extends InterestBearingAccount {
    @Override public String getAccountType() { return "FD"; }
    @Override public List<String> generateAuditReport() { /* FD-specific */ }
    @Override public BigDecimal calculateTax() { /* different tax rules for FD */ }
}
// Both SavingsAccount and FixedDepositAccount share:
// - Account state (accountId, balance, deposit)
// - InterestBearingAccount behavior (calculateMonthlyInterest)
// - Auditable and Taxable capabilities
// But each provides its own getAccountType(), audit report, and tax calculation.

What are common mistakes?

The most common mistake is forgetting that the concrete subclass must implement all remaining abstract methods.

JAVA
// WRONG: concrete class missing abstract method implementation
// public class SavingsAccount extends InterestBearingAccount {
//     @Override public String getAccountType() { return "SAVINGS"; }
//     // Missing: generateAuditReport() and calculateTax()
//     // Compile error: "SavingsAccount is not abstract and does not override..."
// }

What should a senior engineer know?

DIAGRAM
- This layered pattern maps directly to Domain-Driven Design aggregate hierarchies.
- In JPA, a base entity class can be abstract with @MappedSuperclass, extended by domain-specific abstract classes, and finally by concrete entities.
- In Spring, this pattern is used in AbstractController -> AbstractAnnotationConfigDispatcherServletInitializer hierarchies.

Visual Overview

DIAGRAM
  LAYERED HIERARCHY
  ──────────────────────────────────────────

  Layer 1: Account (abstract)
  ┌─────────────────────────────────┐
  │ fields: accountId, balance       │
  │ concrete: deposit()              │
  │ abstract: getAccountType()       │
  └──────────────┬──────────────────┘
                 │ extends
  Layer 2: InterestBearingAccount (abstract)
  ┌─────────────────────────────────┐
  │ implements Auditable, Taxable    │
  │ fields: annualRate               │
  │ concrete: calculateMonthlyInterest()│
  │ abstract: getAccountType()       │
  │ abstract: generateAuditReport()  │
  │ abstract: calculateTax()         │
  └──────────────┬──────────────────┘
                 │ extends
  Layer 3: SavingsAccount (concrete)
  ┌─────────────────────────────────┐
  │ implements ALL remaining methods │
  │ getAccountType() -> "SAVINGS"    │
  │ generateAuditReport() -> [...]   │
  │ calculateTax() -> 30% of interest│
  └─────────────────────────────────┘

Key Takeaway

Yes, an abstract class can simultaneously extend one other class and implement multiple interfaces. It does not need to implement all interface methods: being abstract, it can leave unimplemented methods for concrete subclasses. This creates a layered hierarchy where each layer adds more specificity: Account (base state) to InterestBearingAccount (adds interest and declares Auditable and Taxable) to SavingsAccount (provides all remaining implementations).

In Pankaj's banking system at National Bank of India, InterestBearingAccount extends Account (inheriting accountId, balance, deposit) and implements Auditable plus Taxable. It provides calculateMonthlyInterest() but leaves calculateTax() and getAccountType() abstract, so it must be declared abstract. SavingsAccount extends InterestBearingAccount and implements both remaining methods, making it concrete. FixedDepositAccount does the same with different tax rules.

Remember one sentence: an abstract class can extend one class and implement multiple interfaces, leaving unimplemented methods for concrete subclasses, which creates a layered hierarchy from general to specific.

---

Share
Use ← → arrow keys to navigate