🧬 Inheritance & Polymorphism · Intermediate

extends & is-a in Java

A subclass inherits non-private members; single class inheritance.

🧩 The mysteryWrite eat() once in Animal, and Dogs, Cats and Parrots all know how to eat — without a single copied line. That's the promise of inheritance. But it comes with strict rules.

The is-a relationship

class Dog extends Animal says every Dog is an Animal. The subclass inherits the superclass's accessible fields and methods and can add its own on top.

class Animal {
    void eat() { System.out.println("nom"); }
}
class Dog extends Animal {
    void bark() { System.out.println("woof"); }
}
// a Dog can eat() AND bark()
🔮 Predict it

Inherited for free

Truck declares nothing at all. What prints?

class Vehicle {
    int wheels = 4;
    String honk() { return "beep"; }
}
class Truck extends Vehicle { }
void main() {
    Truck t = new Truck();
    System.out.print(t.wheels + " ");
    System.out.println(t.honk());
}
  1. 4 beep
  2. Compile error
  3. 0 null
Show the answer

4 beep. Truck inherits the wheels field and the honk() method from Vehicle — it's a Vehicle, after all.

🤔 Think first

Good or bad extends?

Does class Car extends Wheel make sense?

Think about it, then reveal the answer

No. Try the sentence "every Car is a Wheel" — nonsense. A car has wheels. That's a *has-a* relationship, modeled with a field (composition), not extends. Compare Cat extends Animal or SavingsAccount extends Account: true is-a sentences.

One parent only

A Java class has exactly one direct superclass — class C extends A, B doesn't compile. This is *single inheritance*. (A class can implement many interfaces, coming in the next world.) No extends at all means extends Object.

⚠️ The trap

Private stays private

Private members are not inherited in the sense of being accessible. Every B object *contains* secret, but code in B can't touch it — this is a compile error.

class A { private int secret = 42; }
class B extends A {
    int peek() {
        return secret; // error!
    }
}

Constructors aren't inherited

Even if Animal has an Animal(String name) constructor, new Dog("Rex") doesn't work automatically. Constructors are never inherited: Dog must declare its own and pass the value up.

class Dog extends Animal {
    Dog(String name) {
        super(name);
    }
}
💼 In the real world

In real projects

The extends you'll write most often is a custom exception: class InsufficientFundsException extends Exception. Frameworks also hand you base classes to extend — but modern code uses inheritance sparingly, only for true is-a relationships.

Key takeaways

  1. extends models an is-a relationship
  2. Non-private members are inherited
  3. Private members exist in the object but are not accessible
  4. Only one superclass per class; constructors aren't inherited
🤯 Did you know?

Java chose single class inheritance partly to avoid C++'s "diamond problem", where two parents provide the same method and it's unclear which one a child should get.

Practice questions

What does this print?

class Animal {
    String name = "animal";
    String sound() { return "noise"; }
}
class Dog extends Animal { }
void main() {
    Dog d = new Dog();
    System.out.println(d.name + " " + d.sound());
}
  1. animal noise
  2. Compile error
  3. null null
  4. dog noise
Check your answer

animal noise. Dog declares nothing itself, but it inherits the name field and the sound() method from Animal.

Which of these is NOT a sensible is-a relationship for extends?

  1. Car extends Wheel
  2. Cat extends Animal
  3. SavingsAccount extends Account
  4. Square extends Shape
Check your answer

Car extends Wheel. A car has wheels; it is not a kind of wheel. That is a has-a relationship and should be a field (composition).

Next: the child wants to *extend* the parent's behavior, not replace it. Meet super.