Java inheritance and method overriding

Use a superclass reference to call subclass behavior.

Java
class Animal {
    String speak() { return "sound"; }
}
class Dog extends Animal {
    @Override String speak() { return "woof"; }
}
class Cat extends Animal {
    @Override String speak() { return "meow"; }
}
class Main {
    public static void main(String[] args) {
        Animal[] animals = {new Dog(), new Cat()};
        for (Animal animal : animals) {
            System.out.println(animal.speak());
        }
    }
}
Output
woof
meow

Explanation

extends establishes a superclass relationship. An overriding instance method replaces inherited behavior for that object's runtime type.

The @Override annotation asks the compiler to check that a method really overrides an inherited declaration. The reference type controls available operations; the runtime object controls virtual instance-method dispatch.

Explore the dry run
Guided walkthroughReady
1class Animal {
2 String speak() { return "sound"; }
3}
4class Dog extends Animal {
5 @Override String speak() { return "woof"; }
6}
7class Cat extends Animal {
8 @Override String speak() { return "meow"; }
9}
10class Main {
11 public static void main(String[] args) {
12 Animal[] animals = {new Dog(), new Cat()};
13 for (Animal animal : animals) {
14 System.out.println(animal.speak());
15 }
16 }
17}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Store two subclass references in a superclass-typed array.animals = [Dog, Cat]
—
The first call dispatches to Dog.return = woof
—
Print the first sound.return = woof
woof
The next iteration dispatches to Cat.return = meow
woof
Print the second sound.return = meow
woof
meow

Cost and common mistakes

O(n) calls for n objects, O(n) array storage.

  • Overloading chooses among parameter signatures; overriding supplies subclass behavior for the same signature.
  • Static methods do not use this instance dispatch behavior.

Try it yourself

Add Bird extends Animal with speak returning chirp.

Reveal answer and reasoning

Adding new Bird() to the array makes the loop print chirp as another line.

Further reading