Inheritance

IB Syllabus: B3.2 (HL) – Implement inheritance using extends and super.

HL Only – This page covers content assessed at HL level only.

Table of Contents

  1. Key Concepts
    1. What is Inheritance?
    2. The extends Keyword
    3. The super Keyword
    4. What is Inherited?
    5. Constructor Chaining
    6. Advantages of Inheritance
    7. Disadvantages of Inheritance
    8. UML Notation
  2. Worked Examples
    1. Example 1: Building a Class Hierarchy
    2. Example 2: The Racer Hierarchy
  3. Quick Check
  4. Trace Exercise
  5. Spot the Error
  6. Predict the Output
  7. Practice Exercises
    1. Core
    2. Extension
    3. Challenge
  8. Connections

Key Concepts

What is Inheritance?

Inheritance allows a new class (the child or subclass) to reuse and extend the attributes and methods of an existing class (the parent or superclass). The child class inherits everything from the parent and can add new attributes, new methods, or change existing behaviour.

This is an “is-a” relationship: a Dog IS-A Animal, a SavingsAccount IS-A BankAccount, a Hare IS-A Racer.

// Parent class
public class Animal {
    private String name;
    private int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    public String speak() {
        return "...";
    }
}

// Child class -- inherits name, age, getName(), getAge(), speak()
public class Dog extends Animal {
    private String breed;

    public Dog(String name, int age, String breed) {
        super(name, age);  // call the parent constructor
        this.breed = breed;
    }

    public String getBreed() { return breed; }

    // Override the parent's speak() method
    @Override
    public String speak() {
        return "Woof!";
    }
}
Dog d = new Dog("Max", 3, "Labrador");
System.out.println(d.getName());   // Max -- inherited from Animal
System.out.println(d.getAge());    // 3 -- inherited from Animal
System.out.println(d.getBreed());  // Labrador -- defined in Dog
System.out.println(d.speak());     // Woof! -- overridden in Dog

The Dog class did not define getName() or getAge() – it inherited them from Animal. It added breed and getBreed(), and overrode speak() to provide dog-specific behaviour.

The extends Keyword

extends declares that a class inherits from another:

public class Dog extends Animal { ... }
//           child    parent

Java supports single inheritance only – a class can extend exactly one parent. It cannot extend two classes simultaneously.

The super Keyword

super refers to the parent class. It has two main uses:

1. Calling the parent constructor:

public Dog(String name, int age, String breed) {
    super(name, age);  // calls Animal(String, int)
    this.breed = breed;
}

The super(...) call MUST be the first line in the child constructor. It passes values to the parent constructor to initialise the inherited attributes. If you do not call super(...), Java automatically calls super() (the no-argument parent constructor) – which will fail if the parent does not have one.

2. Calling a parent method:

@Override
public String speak() {
    return super.speak() + " Woof!";  // calls Animal's speak() then adds to it
}

super(...) must be the first statement in a child constructor. This ensures the parent part of the object is initialised before the child adds its own attributes. Forgetting this is a common compile error.

What is Inherited?

A child class inherits:

  • All public and protected methods
  • All public and protected attributes
  • The parent’s public interface

A child class does NOT inherit:

  • private attributes (they exist in the object but cannot be accessed directly – use getters)
  • Constructors (the child must define its own and call super(...))
public class Animal {
    private String name;     // NOT directly accessible in Dog
    protected int age;       // accessible in Dog

    public String getName() { return name; }  // inherited by Dog
}

public class Dog extends Animal {
    public void printInfo() {
        // System.out.println(name);  // ERROR -- name is private in Animal
        System.out.println(getName()); // OK -- getName() is public
        System.out.println(age);       // OK -- age is protected
    }
}

Constructor Chaining

When you create a Dog, Java must first create the Animal part of the object. This is constructor chaining – the child constructor calls the parent constructor, which initialises the parent attributes before the child constructor initialises its own.

new Dog("Max", 3, "Labrador")
    │
    ▼
Dog constructor runs:
    │
    ├── super("Max", 3)  →  Animal constructor sets name="Max", age=3
    │
    └── this.breed = "Labrador"  →  Dog constructor sets breed

Advantages of Inheritance

Advantage How
Code reuse Common attributes and methods are written once in the parent, inherited by all children
Extensibility New child classes can be added without modifying existing code
Maintainability Fixing a bug in the parent automatically fixes it in all children
Logical hierarchy Reflects real-world relationships (Dog is-a Animal, Car is-a Vehicle)

Disadvantages of Inheritance

Disadvantage How
Tight coupling Child depends on parent’s implementation; changes to the parent can break children
Fragile base class Modifying a parent class can have unintended effects on all subclasses
Limited flexibility Java allows only single inheritance – a class can have only one parent

Inheritance creates “is-a” relationships and enables code reuse, extensibility, easier debugging, and maintainability. These are the exact advantages IB mark schemes award marks for.

UML Notation

Inheritance is shown with a solid line and a closed triangle pointing to the parent:

+------------------+
|     Animal       |
+------------------+
| - name: String   |
| - age: int       |
+------------------+
| + getName(): ... |
| + speak(): ...   |
+------------------+
        △
        |
+------------------+
|      Dog         |
+------------------+
| - breed: String  |
+------------------+
| + getBreed(): ...|
| + speak(): ...   |
+------------------+

Worked Examples

Example 1: Building a Class Hierarchy

Scenario: A school has different types of people: students and teachers. Both have names and ages. Students have a grade; teachers have a subject.

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
}

public class Student extends Person {
    private int grade;

    public Student(String name, int age, int grade) {
        super(name, age);
        this.grade = grade;
    }

    public int getGrade() { return grade; }
}

public class Teacher extends Person {
    private String subject;

    public Teacher(String name, int age, String subject) {
        super(name, age);
        this.subject = subject;
    }

    public String getSubject() { return subject; }
}
Student s = new Student("Alice", 16, 11);
Teacher t = new Teacher("Mr. Smith", 35, "CS");

System.out.println(s.getName() + " Grade " + s.getGrade());
System.out.println(t.getName() + " teaches " + t.getSubject());

Output:

Alice Grade 11
Mr. Smith teaches CS

Both Student and Teacher inherit getName() and getAge() from Person. Each adds its own specific attribute and getter.

Example 2: The Racer Hierarchy

Inspired by the classic IB teaching example:

public class Racer {
    private String name;
    private int position;

    public Racer(String name) {
        this.name = name;
        this.position = 0;
    }

    public String getName() { return name; }
    public int getPosition() { return position; }

    public void move() {
        position = position + 1;  // default: move 1 step
    }
}

public class Hare extends Racer {
    public Hare(String name) {
        super(name);
    }

    @Override
    public void move() {
        // 30% chance of jumping 5 steps, 70% chance of sleeping
        if (Math.random() < 0.3) {
            // Jump forward 5 positions
            for (int i = 0; i < 5; i++) {
                super.move();  // reuse parent's move()
            }
        }
        // else: do nothing (sleep)
    }
}

public class Tortoise extends Racer {
    public Tortoise(String name) {
        super(name);
    }

    @Override
    public void move() {
        super.move();  // always moves exactly 1 step
    }
}

The Hare and Tortoise both IS-A Racer but override move() with different strategies. This sets up polymorphism (covered in the next page).


Quick Check

Q1. Which keyword is used to create a child class from a parent class?

Q2. Where must super(...) appear in a child constructor?

Q3. Can a child class directly access a parent's private attributes?

Q4. Which is an advantage of inheritance?

Q5. Which is a disadvantage of inheritance?


Trace Exercise

Trace the creation of a Student object. Track how constructor chaining works.

Trace: Constructor Chaining

Student s = new Student("Alice", 16, 11);

What happens in order?

StepConstructornameagegrade
1. super("Alice", 16) called --
2. this.grade = 11

Spot the Error

This code does not compile. The constructor is missing a required call. Click the line where the missing statement should be inserted, then pick the fix.

1public class Student extends Person { 2 private int grade; 3 public Student(String name, int age, int grade) { 4 this.grade = grade; 5 } 6}

Pick what should be added before this.grade = grade;:


Predict the Output

What does this print?

Dog d = new Dog("Max", 3, "Labrador");
System.out.println(d.getName() + " says " + d.speak() + " (" + d.getBreed() + ")");

Practice Exercises

Core

  1. Build a hierarchy – Create a Vehicle parent class with make (String), year (int), and getDescription(). Create two child classes: Car (adds numDoors) and Motorcycle (adds hasSidecar boolean). Each child should call super(...) in its constructor.

  2. Identify inheritance – For each pair, state whether inheritance is appropriate and explain why:
    • (a) Textbook and Book
    • (b) Laptop and Battery
    • (c) Teacher and Person
    • (d) Playlist and Song
  3. Trace constructor chaining – Given Vehicle -> Car -> ElectricCar, trace what happens when you create an ElectricCar("Tesla", 2024, 4, 350) where 350 is the battery range in km. Show which constructor runs first.

Extension

  1. Override a method – Add a getDescription() method to both Car and Motorcycle that overrides the parent’s version. Car’s should include door count; Motorcycle’s should mention the sidecar status. Use super.getDescription() to include the parent’s output.

  2. Advantages and disadvantages – A student argues that inheritance should be used whenever two classes share any attributes. Explain why this is wrong, giving an example of when aggregation would be more appropriate even though the classes share attributes.

Challenge

  1. Full system with inheritance – Design a banking system with BankAccount (parent), SavingsAccount (adds interest rate and addInterest() method), and CheckingAccount (adds overdraft limit and modified withdraw() that allows negative balance up to the limit). Draw the UML and implement all three classes.

Connections

  • Prerequisites: Classes and Objects – creating classes with attributes and methods
  • Prerequisites: Constructors – understanding how constructors initialise objects
  • Prerequisites: Aggregation – understanding when to use has-a vs is-a
  • Next: Method Overriding – deeper dive into @Override and changing parent behaviour
  • Forward: Polymorphism – using parent-type references to hold child objects

Back to top

© EduCS.me — A resource hub for IB Computer Science

This site uses Just the Docs, a documentation theme for Jekyll.