Method Overriding
IB Syllabus: B3.2 (HL) – Override methods in subclasses to provide specialised behaviour.
HL Only – This page covers content assessed at HL level only.
Table of Contents
- Key Concepts
- Worked Examples
- Quick Check
- Spot the Error
- Predict the Output
- Practice Exercises
- Connections
Key Concepts
What is Method Overriding?
When a child class defines a method with the same name, same parameters, and same return type as a method in its parent class, the child’s version replaces the parent’s version for objects of the child type. This is method overriding.
public class Animal {
public String speak() {
return "...";
}
}
public class Dog extends Animal {
@Override
public String speak() {
return "Woof!";
}
}
public class Cat extends Animal {
@Override
public String speak() {
return "Meow!";
}
}
Dog d = new Dog();
Cat c = new Cat();
Animal a = new Animal();
System.out.println(d.speak()); // Woof!
System.out.println(c.speak()); // Meow!
System.out.println(a.speak()); // ...
Each subclass provides its own version of speak(). When you call speak() on a Dog, Java uses the Dog’s version, not the Animal’s.
The @Override Annotation
@Override is an annotation placed above a method to tell the compiler “I intend to override a parent method.” It is optional but strongly recommended because:
- If you misspell the method name, the compiler catches it immediately
- If you accidentally change the parameter types, the compiler warns you
- It makes the code easier to read – anyone reading the class knows this method replaces a parent’s version
@Override
public String speak() { // compiler checks: does Animal have speak()?
return "Woof!";
}
Without @Override, a typo like speek() would create a NEW method instead of overriding the parent’s speak(). The code would compile but behave incorrectly – a subtle bug.
Always use
@Overridewhen overriding a method. It costs nothing and prevents hard-to-find bugs. IB mark schemes expect to see it.
Overriding Rules
For a method to override a parent method, it must have:
- Same method name as the parent
- Same parameter list (number, types, and order)
- Same return type (or a subtype)
- Same or less restrictive access modifier (e.g., a
protectedparent method can be overridden aspublic, but not asprivate)
If any of these differ, it is not an override – it is a new method (overloading or a completely separate method).
Overriding vs Overloading
These are often confused but are fundamentally different:
| Overriding | Overloading | |
|---|---|---|
| Where | Child class redefines a parent method | Same class defines multiple methods with the same name |
| Parameters | Must be identical to the parent | Must be different (different number or types) |
| Return type | Must be the same (or subtype) | Can be different |
| Which runs? | Decided at runtime (based on actual object type) | Decided at compile time (based on parameter types) |
| Purpose | Specialise behaviour for a subtype | Provide multiple ways to call the same operation |
// OVERLOADING -- same class, different parameters
public class Calculator {
public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; }
}
// OVERRIDING -- child class, same method signature
public class Animal {
public String speak() { return "..."; }
}
public class Dog extends Animal {
@Override
public String speak() { return "Woof!"; } // same name, same params
}
Calling the Parent’s Version with super
Sometimes you want to extend the parent’s behaviour rather than completely replace it. Use super.methodName() to call the parent’s version from inside the override:
public class Employee {
private String name;
private double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
public double calculatePay() {
return baseSalary;
}
public String toString() {
return name + ": $" + calculatePay();
}
}
public class Manager extends Employee {
private double bonus;
public Manager(String name, double baseSalary, double bonus) {
super(name, baseSalary);
this.bonus = bonus;
}
@Override
public double calculatePay() {
return super.calculatePay() + bonus; // parent's pay + bonus
}
}
Employee e = new Employee("Alice", 50000);
Manager m = new Manager("Bob", 60000, 10000);
System.out.println(e.calculatePay()); // 50000.0
System.out.println(m.calculatePay()); // 70000.0 (60000 + 10000)
The Manager’s calculatePay() reuses the parent’s calculation via super.calculatePay() and adds the bonus on top. This avoids duplicating the base salary logic.
toString() Override
Every Java class inherits a toString() method from Object (the root of all Java classes). By default, it returns something unhelpful like Student@1a2b3c. Overriding it lets you define a meaningful string representation:
public class Student {
private String name;
private int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
@Override
public String toString() {
return name + " (Grade " + grade + ")";
}
}
Student s = new Student("Alice", 11);
System.out.println(s); // Alice (Grade 11)
// Without override: Student@7a81197d
System.out.println() automatically calls toString() on objects. Overriding it makes debugging and output much easier.
Worked Examples
Example 1: Shape Hierarchy
public class Shape {
public double getArea() {
return 0;
}
public String describe() {
return "Shape with area " + getArea();
}
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
}
Circle c = new Circle(5);
Rectangle r = new Rectangle(4, 6);
System.out.println(c.describe()); // Shape with area 78.53981633974483
System.out.println(r.describe()); // Shape with area 24.0
Notice: describe() is NOT overridden – it is inherited from Shape. But it calls getArea(), which IS overridden. So when c.describe() runs, it calls the Circle’s getArea(), not the Shape’s. This is the power of overriding.
Quick Check
Q1. What is method overriding?
Q2. Why should you use @Override?
Q3. A parent has void print(String s). A child defines void print(int n). Is this overriding?
Q4. What does super.calculatePay() do inside an overridden method?
Spot the Error
A student wants Dog to override Animal's speak() method, but calling d.speak() still returns "..." (the parent's version). Click the buggy line, then pick the fix.
Pick the fix:
Predict the Output
Using the Employee/Manager classes from the Key Concepts section:
Manager m = new Manager("Bob", 60000, 10000);
System.out.println(m.calculatePay()); Using the Shape/Circle classes from Example 1, what does c.describe() start with?
Circle c = new Circle(5);
System.out.println(c.describe());Does the output start with "Shape" or "Circle"?
Practice Exercises
Core
-
Override toString() – Create a
Bookclass with title and author. OverridetoString()to return"Title by Author". Create a Book and print it directly withSystem.out.println(book). -
Identify override vs overload – For each pair, state whether the child method overrides or overloads the parent:
- (a) Parent:
void draw(), Child:void draw() - (b) Parent:
int calculate(int x), Child:int calculate(int x, int y) - (c) Parent:
String getName(), Child:String getName() - (d) Parent:
void print(String s), Child:void print(int n)
- (a) Parent:
Extension
-
Extend with super – Create a
Vehicleclass withgetDescription()returning"Vehicle: [make]". Create aCarsubclass that overridesgetDescription()to return the parent’s description plus" (4 doors)". Usesuper.getDescription(). -
The describe() trick – In Example 1,
Shape.describe()callsgetArea(). Explain whyc.describe()(where c is a Circle) uses Circle’sgetArea()even thoughdescribe()is defined in Shape. What OOP principle makes this work?
Challenge
- Payment system – Create a class hierarchy:
Employee(base salary),Manager(base + bonus),SalesPerson(base + commission percentage * sales total). All overridecalculatePay(). Create an array of Employees, fill it with a mix of types, and calculate the total payroll.
Connections
- Prerequisites: Inheritance – must understand
extendsandsuperbefore overriding - Next: Polymorphism – overriding enables polymorphic behaviour
- Related: Constructors – constructor overloading vs method overriding