Week 2

Inheritance

Interfaces

Polymorphism

Error Handling in Java

Practice

Assignment

Back end Track

🎯 Learning Objectives

By the end of this module, you will be able to:


1. What is Inheritance?

Inheritance is a mechanism that lets one class acquire the fields and methods of another. It models an "is-a" relationship — if you can truthfully say "A is a B", inheritance is likely the right tool.

Some examples:

The last example is important. "Has-a" relationships should use composition (a field), not inheritance. Choosing the wrong one is one of the most common OOP design mistakes.

🔍 You saw inheritance in JavaScript with class Dog extends Animal. Java works the same way conceptually — the syntax is nearly identical, but Java enforces stricter rules around types and access that make the structure more explicit.

Without inheritance, you'd have to repeat shared fields and methods in every class:

// Without inheritance — duplicated code
public class Dog {
    String name;
    int age;
    public void eat() { System.out.println("Eating..."); }
    public void bark() { System.out.println("Woof!"); }
}

public class Cat {
    String name; // duplicated
    int age;     // duplicated
    public void eat() { System.out.println("Eating..."); } // duplicated
    public void meow() { System.out.println("Meow!"); }
}

With inheritance, shared code lives in one place:

// With inheritance — shared code defined once
public class Animal {
    String name;
    int age;
    public void eat() { System.out.println("Eating..."); }
}

public class Dog extends Animal {
    public void bark() { System.out.println("Woof!"); }
}

public class Cat extends Animal {
    public void meow() { System.out.println("Meow!"); }
}

2. The extends Keyword

Use extends to declare that one class inherits from another:

public class SubClass extends SuperClass {
    // SubClass now has everything SuperClass has, plus its own additions
}

The class being extended is called the superclass (parent). The class doing the extending is called the subclass (child).

public class Animal {           // superclass
    String name;
    int age;

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

public class Dog extends Animal {   // subclass
    public void bark() {
        System.out.println(name + " says: Woof!"); // name inherited from Animal
    }
}
Dog dog = new Dog();
dog.name = "Rex";   // inherited field
dog.age  = 3;       // inherited field
dog.eat();          // inherited method → Rex is eating.
dog.bark();         // own method → Rex says: Woof!

<aside> 💭

Java supports single inheritance only — a class can extend at most one other class. This is different from some other languages (like C++) that allow multiple inheritance. Java addresses this limitation with interfaces, which you'll cover in the next chapter.

</aside>


3. What is Inherited (and What is Not)

Not everything from the superclass is automatically available in the subclass:

Member Inherited? Notes
public fields ✅ Yes Directly accessible
protected fields ✅ Yes Accessible in subclass
public methods ✅ Yes Can be called and overridden
protected methods ✅ Yes Can be called and overridden
private fields ❌ No Exist in memory but not directly accessible — use getters
private methods ❌ No Not accessible in subclass
Constructors ❌ No Must be defined separately in each class
public class Animal {
    private String name;   // private — not directly accessible in subclass
    protected int age;     // protected — accessible in subclass

    public String getName() { return name; }   // public getter — inherited ✅
    public void setName(String name) { this.name = name; }
}

public class Dog extends Animal {
    public void describe() {
        // System.out.println(name);      // ❌ private — not accessible
        System.out.println(getName());    // ✅ use the inherited getter
        System.out.println(age);         // ✅ protected — directly accessible
    }
}

<aside> 💭

This is why encapsulation and inheritance work together — making fields private and exposing them through public/protected methods keeps the superclass in control of its own data even as subclasses extend it.

</aside>


4. The super Keyword — Calling the Parent Constructor

Since constructors are not inherited, each subclass must define its own. But often a subclass constructor needs to initialise the fields defined in the superclass. The super() call delegates this to the parent constructor.

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 class Dog extends Animal {
    private String breed;

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

    public String getBreed() { return breed; }
}
Dog dog = new Dog("Rex", 3, "Labrador");
System.out.println(dog.getName());  // Rex
System.out.println(dog.getAge());   // 3
System.out.println(dog.getBreed()); // Labrador

Rules for super():

<aside> 💭

In JavaScript, you also call super() at the top of a subclass constructor before using this. Java enforces the same rule — the difference is Java will refuse to compile if you forget.

</aside>


5. super for Calling Parent Methods

super isn't only for constructors. You can also use it to call a method from the superclass when you've overridden it in the subclass and still want to use the parent's version:

public class Animal {
    public void describe() {
        System.out.println("I am an animal.");
    }
}

public class Dog extends Animal {
    @Override
    public void describe() {
        super.describe();                   // calls Animal's describe()
        System.out.println("I am a dog."); // adds Dog-specific behaviour
    }
}
Dog dog = new Dog();
dog.describe();
// I am an animal.
// I am a dog.

This is useful when you want to extend the parent's behaviour rather than completely replace it.


6. Method Overriding

Overriding means redefining a method from the superclass in the subclass with the same signature (same name, same parameters, same return type) but different behaviour.

public class Animal {
    public String makeSound() {
        return "Some generic sound";
    }
}

public class Dog extends Animal {
    @Override
    public String makeSound() {
        return "Woof!";
    }
}

public class Cat extends Animal {
    @Override
    public String makeSound() {
        return "Meow!";
    }
}
Animal a = new Animal();
Animal d = new Dog();
Animal c = new Cat();

System.out.println(a.makeSound()); // Some generic sound
System.out.println(d.makeSound()); // Woof!
System.out.println(c.makeSound()); // Meow!

Notice that d and c are declared as type Animal, but they run the Dog and Cat versions of makeSound(). This is polymorphism — the ability to treat different objects through a common type, and have each respond in its own way. You'll go deeper into this in the next module.

Rules for overriding:


7. The @Override Annotation

@Override is placed above a method to tell the compiler: "I intend this method to override one from the superclass."

@Override
public String makeSound() {
    return "Woof!";
}

It is not required — the override happens with or without it. But it gives you two important benefits:

  1. Compile-time safety — if the signature doesn't match any parent method (e.g. you made a typo), the compiler throws an error immediately. Without @Override, Java would silently create a new method instead of overriding, which is a very hard bug to spot.
  2. Readability — it signals to anyone reading the code that this method has a parent version.
// Without @Override — typo goes undetected
public String makesound() {   // lowercase 's' — not an override, a new method
    return "Woof!";
}

// With @Override — compiler catches the typo immediately
@Override
public String makesound() {   // ❌ Compile error: method does not override
    return "Woof!";
}

<aside> 💡

</aside>


8. Method Overloading vs Method Overriding

Abstract Classes