Back to Upcasting & Dispatch
Q2Question 2 of 2

What is a base class and how does it differ from a derived class?

Key Concepts
  • Base class (parent/superclass): defines common state and behavior shared by all subtypes
  • Derived class (child/subclass): extends the base, adds or overrides specific behavior
  • extends keyword: class SavingsAccount extends Account – inherits all non-private members
  • IS-A relationship: a SavingsAccount IS-A Account – can be used anywhere an Account is expected
  • Object is the implicit base class of every Java class

Definition

A base class defines shared state and behavior. A derived class extends it, inheriting everything and adding or overriding specific behavior. This is the IS-A relationship.

Inheritance hierarchy:

  • Base class (parent): Defines common fields (accountId, balance) and methods (getBalance, debit).
  • Derived class (child): Uses extends to inherit the base class. Adds new fields (interestRate) and can override methods (calculateInterest).
  • IS-A: SavingsAccount IS-A Account. It can be used anywhere Account is expected.

The base class Account is the standard bank template. SavingsAccount and CurrentAccount are specialized versions that inherit the template and add their own features.

Understanding the Concepts

Base and derived class example

JAVA
// Base class
public class Account {
    protected String accountId;
    protected BigDecimal balance;

    public Account(String accountId, BigDecimal balance) {
        this.accountId = accountId;
        this.balance = balance;
    }

    public void debit(BigDecimal amount) {
        balance = balance.subtract(amount);
    }

    public BigDecimal getBalance() { return balance; }
}

// Derived class
public class SavingsAccount extends Account {
    private double interestRate;

    public SavingsAccount(String accountId, BigDecimal balance, double rate) {
        super(accountId, balance);  // call base constructor
        this.interestRate = rate;
    }

    public BigDecimal calculateInterest() {
        return balance.multiply(BigDecimal.valueOf(interestRate / 100));
    }
}

// IS-A: SavingsAccount can be used as Account
Account a = new SavingsAccount("SAV2001", new BigDecimal("500000"), 4.0);
a.debit(new BigDecimal("50000"));  // inherited method

What does a derived class inherit?

| Inherited | Not inherited |
|---|---|
| public and protected fields | private fields (exist but not accessible) |
| public and protected methods | private methods |
| Default (package-private) if same package | Constructors (must call super()) |

What should a senior engineer know?

  • Prefer composition over inheritance when the IS-A relationship is not clear. Use has-a (field) instead of is-a (extends).
  • Abstract base classes define the contract without full implementation.
  • Sealed classes (Java 17+) control which classes can extend the base: sealed class Account permits SavingsAccount, CurrentAccount.

What are common mistakes?

A common mistake is not understanding the concept fully before using it in production banking applications.

Wrong approach:

JAVA
package com.bank.service;

public class TransferService {
    public void transfer(String fromAccount, String toAccount, double amount) {
        // WRONG: using double for money
        double balance = getBalance(fromAccount);
        balance = balance - amount;
    }
    private double getBalance(String id) { return 10000.0; }
}

Correct approach:

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class TransferService {
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // CORRECT: using BigDecimal for money
        BigDecimal balance = getBalance(fromAccount);
        balance = balance.subtract(amount);
    }
    private BigDecimal getBalance(String id) { return new BigDecimal("10000.00"); }
}

Always use BigDecimal for monetary calculations in banking systems to avoid floating-point precision errors.

What are the edge cases?

Edge cases can cause unexpected behavior in banking applications. Here are some to watch for.

JAVA
package com.bank.edge;

public class EdgeCaseDemo {
    public static void main(String[] args) {
        // Edge case 1: null handling
        String accountId = null;
        try {
            System.out.println(accountId.length());
        } catch (NullPointerException e) {
            System.out.println("Null account ID");
        }

        // Edge case 2: empty vs null
        String emptyId = "";
        System.out.println(emptyId.isEmpty());  // true
        System.out.println(emptyId == null);     // false

        // Edge case 3: boundary values
        java.math.BigDecimal zero = java.math.BigDecimal.ZERO;
        java.math.BigDecimal negativeBalance = new java.math.BigDecimal("-0.01");
        System.out.println(zero.compareTo(negativeBalance) > 0);  // true
    }
}
TEXT
Null account ID
true
false
true

Always test with null values, empty strings, boundary values, and negative amounts in banking applications.

What are common interview follow-up questions?

Interviewers often follow up with these related questions:

  • How does this concept apply to a high-throughput banking transaction system?
  • What are the performance implications in a production environment?
  • How would you debug issues related to this concept?
  • What tools would you use to monitor this in production?
  • How does this behave differently in Java 8 vs Java 17+?

When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.

Visual Overview

DIAGRAM
  Account (base)
    ├── accountId, balance
    ├── debit(), getBalance()
    │
    ├── SavingsAccount extends Account (derived)
    │     + interestRate
    │     + calculateInterest()
    │
    └── CurrentAccount extends Account (derived)
          + overdraftLimit
          + checkOverdraft()

  IS-A: SavingsAccount IS-A Account
  → can be used anywhere Account is expected

Key Takeaway

A base class defines shared state and behavior. A derived class extends it with the extends keyword, inheriting all non-private members and adding or overriding specific behavior. This creates an IS-A relationship: a SavingsAccount is an Account and can be used anywhere an Account is expected.

One sentence to remember: the base class is the shared template, the derived class specializes it – inheritance means IS-A.

---

Share
Use ← → arrow keys to navigate