Skip to content
Ameen Abozaid
PublishedBEG-022-L01

Reusing behavior with extends

  • Lesson 1 of 7
  • 11 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

In the last module you hid data behind methods so that a class protects its own rules. Your Account class now works well. Then the bank asks for a savings account that earns interest. A savings account still has an owner, a balance, deposits, and withdrawals. Copying the whole Account class and adding one method would work today, and cause trouble tomorrow: every bug fix would have to be made twice.

This lesson introduces inheritance: a new class can be declared as a kind of an existing class and receive its fields and methods automatically. We will use a family tree as the picture. A child gets traits from a parent but can also have traits of its own.

Why this matters: Java frameworks and libraries are full of classes that extend other classes. Reading and writing extends is a basic skill for backend work.

This lesson builds on the previous module: classes, objects, private, and protected. It uses the Account idea you already know.

Learning Objectives

By the end of this lesson you will be able to:

  • Declare a subclass with extends and name the superclass and subclass in a given pair.
  • Say what a subclass receives from its superclass and what it does not (private members, constructors).
  • Add new fields and methods to a subclass.
  • Explain why a Java class has exactly one direct superclass.
  • Apply the is-a test to decide whether extends fits.
  • Read the compiler error produced when a subclass touches a private field of its parent.

Written Explanation

The problem: the same code twice

Imagine Account has an owner, a balance, deposit, and withdraw. A SavingsAccount needs all of that, plus an interest rate. If you copy Account, you now maintain two classes with identical code. When you find a bug in withdraw, you must remember to fix it in both. Programmers call this duplication, and it is a main source of bugs that fix themselves in one place only.

extends: declaring a kind-of relationship

Inheritance lets you write the shared code once. The keyword is extends:

java
class SavingsAccount extends Account {
    // new things only
}

Vocabulary you will see everywhere:

TermMeaningIn the example
Superclass (also parent or base class)The class being extendedAccount
Subclass (also child or derived class)The class that extendsSavingsAccount
Direct superclassThe one named after extendsAccount

The Java tutorial on inheritance describes the subclass as inheriting the members of its superclass, and says it can add fields and methods of its own. In the family-tree picture, SavingsAccount is the child, Account is the parent, and the child receives the parent's traits.

What a subclass receives

When SavingsAccount extends Account, every SavingsAccount object can use the accessible members of Account as if it had written them itself. Whether a member is accessible follows the access rules from the previous module:

Member of the parentDoes the subclass get it?
public fields and methodsYes
protected fields and methodsYes
Package-private (no modifier)Yes, if the subclass is in the same package; otherwise no
private fields and methodsNo (not inherited)
ConstructorsNo (constructors are not members, so they are not inherited)

A private field is the subtle case. The SavingsAccount object does hold the parent's private data inside it, because the object must store the balance somewhere. But the subclass code cannot name that field. It can only reach it through the parent's public or protected methods. That is encapsulation still doing its job: a subclass does not get to break the parent's rules.

Constructors are the other exception. A constructor builds a particular class, so it is not handed down. The next lesson shows how a subclass constructor asks the parent's constructor to do its part.

New members and the family tree

A subclass is the parent plus something. It can add fields and methods that the parent does not have:

java
class SavingsAccount extends Account {
    private double rate;          // new field

    void addInterest() { ... }    // new method
}

A SavingsAccount object has everything from Account and also rate and addInterest(). The reverse is not true: a plain Account has no addInterest(). The parent knows nothing about its children, just as a parent's traits do not depend on what a child later becomes.

One parent only

A Java class has exactly one direct superclass. The language specification (JLS section 8.1.4) says the extends clause names a single class, so you cannot write class C extends A, B. A class without any extends has Object as its direct superclass, and Object is the top of every chain. So every class you have written so far already extends Object without saying so, and every class has a chain of ancestors ending at Object.

A class can have many children; it just cannot have many parents. A class can also implement interfaces, which is a different mechanism and a later topic.

The is-a test

Inheritance is a promise: a subclass object can be treated as a kind of its superclass. Before writing extends, say the sentence out loud:

  • "A savings account is an account." Yes: extends fits.
  • "A dog is an animal." Yes.
  • "A car is an engine." No: a car has an engine.

If the sentence sounds wrong, extends is wrong, however much code it would save. Lesson 5 goes deeper into the alternative. Saving typing is a pleasant side effect of inheritance, not its purpose.

What the compiler says about private parent data

Because private members are not inherited, this does not compile:

java
class Account {
    private double balance = 100;
    double getBalance() { return balance; }
}

class SavingsAccount extends Account {
    void addBonus() {
        balance += 10;
    }
}
text
Main.java:8: error: balance has private access in Account
        balance += 10;
        ^
1 error

The fix is not to make balance public. Add a method to the parent that applies the rule (a deposit), and let the child call it.

Examples

Example 1: Animal and Dog (simple)

java
class Animal {
    String name = "unnamed";

    void eat() {
        System.out.println(name + " is eating");
    }
}

class Dog extends Animal {
    void fetch() {
        System.out.println(name + " fetches the ball");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "Rex";
        d.eat();
        d.fetch();
    }
}

Output:

text
Rex is eating
Rex fetches the ball

Dog never declares name or eat(), yet it uses both. fetch() is new in Dog. (A package-visible field is used here only to keep the first example short; real classes hide their fields.)

Example 2: SavingsAccount reuses Account (practical)

java
class Account {
    private final String owner;
    private double balance;

    Account(String owner, double balance) {
        this.owner = owner;
        this.balance = balance;
    }

    String getOwner() { return owner; }
    double getBalance() { return balance; }

    void deposit(double amount) {
        if (amount <= 0) {
            System.out.println("Deposit refused");
            return;
        }
        balance += amount;
    }
}

class SavingsAccount extends Account {
    private double rate;

    SavingsAccount(String owner, double balance, double rate) {
        super(owner, balance);   // explained in the next lesson
        this.rate = rate;
    }

    void addInterest() {
        deposit(getBalance() * rate);
    }
}

public class Main {
    public static void main(String[] args) {
        SavingsAccount s = new SavingsAccount("Sara", 1000, 0.05);
        s.deposit(100);
        s.addInterest();
        System.out.println(s.getOwner() + " has " + s.getBalance());
    }
}

Output:

text
Sara has 1155.0

SavingsAccount never touches balance directly. It calls the inherited getBalance() and deposit(...), so the parent's rule (no non-positive deposits) still applies to interest. The line super(owner, balance); is a preview: constructors are not inherited, so the child must call the parent's. Lesson 2 explains it fully; for now copy the pattern.

Example 3: Employee and Manager (realistic)

A company system has employees who are paid, and managers who are employees that also manage a team:

java
class Employee {
    String name;
    double salary;
    void pay() { System.out.println(name + " is paid " + salary); }
}

class Manager extends Employee {
    int teamSize;
    void report() { System.out.println(name + " manages " + teamSize + " people"); }
}

Creating a Manager, setting name = "Omar", salary = 3000, teamSize = 4, then calling pay() and report() prints:

text
Omar is paid 3000.0
Omar manages 4 people

If a pay bug appears in Employee.pay(), fixing it once fixes managers too. This is the real benefit: one place to change. Notice that Manager also has methods nobody wrote: calling toString() on a manager works because Employee itself extends Object.

Backend Insight

Backend frameworks are built on "extend this class" ideas. You will meet base classes provided by a framework that your own class extends to plug into it. Understanding what you receive from a parent, and what you must not touch, is how you read that code safely.

Inheritance also affects how long-lived code changes. If a parent class changes, every child changes with it, because they share the code. That is powerful when you fix a bug once. It is dangerous when the parent's authors do not know who extends it. Backend teams therefore choose parents deliberately: a shared base class used by dozens of services is a contract that is expensive to change.

Common Mistakes

Mistake 1: Using extends only to save typing

  • Incorrect: class Invoice extends Account because both have an amount.
  • Correct: ask "is an invoice an account?" Since it is not, keep them separate classes.

Mistake 2: Expecting to inherit private members

A subclass cannot read or write the parent's private fields by name. Use the parent's public or protected methods.

Mistake 3: Expecting to inherit constructors

SavingsAccount does not get Account(String, double). You must write a constructor in the subclass.

Mistake 4: Trying to extend two classes

text
class C extends A, B {}
Main.java:3: error: '{' expected

Java allows a single superclass. Pick the true parent and use other tools (such as holding an object in a field, Lesson 5) for the rest.

Mistake 5: Expecting the parent to know the child's members

An Account object has no addInterest(). The new methods exist only on the subclass.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. Name the superclass and the subclass: class Cat extends Animal.

Show solution A1

A1. Superclass: Animal. Subclass: Cat.

A2. Apply the is-a test and answer yes or no for extends: (a) Teacher / Person, (b) Wheel / Car, (c) Circle / Shape.

Show solution A2

A2. (a) Yes: a teacher is a person. (b) No: a car has wheels. (c) Yes: a circle is a shape.

A3. Can a subclass use a public method of its parent without redeclaring it? A private one?

Show solution A3

A3. A public method: yes, it is inherited. A private one: no, the subclass cannot use it by name.

Level B: Application

B1. Product has name, price, and label() that returns name + " costs " + price. Write DiscountedProduct extends Product with a discount field and a finalPrice() method. What does label() return for a product named Lamp priced 50?

Show solution B1

B1.

java
class DiscountedProduct extends Product {
    double discount;

    double finalPrice() {
        return price - discount;
    }
}

label() is inherited, so for Lamp priced 50 it returns Lamp costs 50.0. (Running a discount of 8 gives finalPrice() of 42.0.)

B2. This does not compile. Explain why and give a fix without making the field public.

java
class Counter { private int count; }
class StepCounter extends Counter {
    void step() { count++; }
}
Show solution B2

B2. count is private in Counter, so StepCounter cannot name it. Fix: give Counter a method such as protected void increment() { count++; } (or a public one) and call increment() from step(). The parent keeps control of its field.

B3. Report has a public print(). PdfReport extends Report adds export(). Which of these calls are valid on a PdfReport object: print(), export()? On a plain Report object?

Show solution B3

B3. On a PdfReport both print() (inherited) and export() are valid. On a plain Report only print() is valid, because the parent does not have export().

Level C: Challenge

C1. A teammate writes class OrderItem extends Order because an order item needs the order's date. Explain what is wrong with the design in two sentences, and say what the item should do instead (a hint is in the Common Mistakes above).

Show solution C1

C1. An order item is not a kind of order: it is a part of one, so the is-a test fails, and a shared date is not a reason to inherit. The item should hold a reference to its Order in a field (or receive the date as a constructor argument) instead of extending it.

C2. Draw the ancestor chain of Manager from Example 3 down to the very top, listing every class.

Show solution C2

C2. Manager extends Employee, which extends Object. So the chain is Manager, Employee, Object.

Mini Challenge

Create a Vehicle class with a field brand (private, with a getter) and a method describe() that prints the brand. Create a Truck extends Vehicle with a loadCapacity field and a method that prints it. In main, create a truck and call both methods. Then add a line inside Truck that reads brand directly, read the compiler error, and remove the line.

Check your work: Truck reuses describe() without redeclaring it, and the direct access to brand is rejected by the compiler.

Summary & Next Lesson

Key takeaways

  • class Child extends Parent makes Child a subclass that receives the accessible members of Parent and can add its own.
  • Private members and constructors are not inherited.
  • A class has exactly one direct superclass; a class with no extends has Object as its superclass.
  • Use the is-a test before extends. Code reuse alone is not a reason.
  • Fix a bug in the parent once and all children benefit, which is both the strength and the risk.

Next lesson

You saw super(owner, balance) once, as a preview. The next lesson, "Constructors and super", explains how the parent part of an object is built and what the compiler requires.

Self-check

  1. Which keyword makes one class a subclass of another?
  2. Can a class have two direct superclasses?
  3. Is a private field of the parent inherited by name? What gives the child access?
  4. Which class is at the top of every class's ancestor chain?
  5. A Library class holds many Book objects. Does Library extends Book pass the is-a test?
Show answers
  1. extends.
  2. No. Exactly one direct superclass.
  3. No. The child uses the parent's public or protected methods.
  4. Object.
  5. No. A library is not a kind of book; it has books.

References

  • Oracle, Java Tutorials, Inheritance. Supports what a subclass inherits: public and protected members, not private members or constructors, and the idea of adding new members.
  • Oracle, Java Language Specification SE 21, Section 8.1.4, Superclasses and Subclasses. Supports the single direct superclass rule and Object as the default superclass.
  • The family-tree analogy, the is-a test wording, and the Account examples are this course's own teaching choices. The code was compiled and run with JDK 21 and the output shown is real.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.