CodeMIRAI
0 XP

Inheritance

2 min read 3 runnable examples Quiz included

Inheritance lets a class build on another: the subclass gets the superclass's fields and methods, and can add new ones or change inherited ones.

ObjectAnimalDogCatevery class extends ObjectextendsextendsDog and Cat inherit Animal's fields and methods, and can override them
Arrows point to the parent class. A Dog is an Animal, so a Dog can go wherever an Animal is expected.
Java
class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

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

    void speak() {
        System.out.println(name + " makes a sound.");
    }
}

class Dog extends Animal {
    Dog(String name) {
        super(name);                     // run Animal's constructor
    }

    void fetch() {                       // a new method that only dogs have
        System.out.println(name + " fetches the ball!");
    }

    @Override
    void speak() {                       // replaces the inherited version
        System.out.println(name + " barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog rex = new Dog("Rex");
        rex.eat();      // inherited from Animal
        rex.speak();    // overridden in Dog
        rex.fetch();    // only in Dog
    }
}

super

  • super(...) calls the parent's constructor, and must be the first statement in the subclass constructor. If you don't write one, Java inserts super() for you, which fails to compile when the parent has no constructor without parameters.
  • super.method() calls the parent's version of a method you've overridden:
Java
class Employee {
    String name;
    double salary;

    Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    double monthlyPay() {
        return salary / 12;
    }

    String describe() {
        return name + " earns " + Math.round(monthlyPay()) + " a month";
    }
}

class Manager extends Employee {
    double bonus;

    Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    @Override
    double monthlyPay() {
        return super.monthlyPay() + bonus / 12;     // normal pay, plus the bonus
    }
}

public class Main {
    public static void main(String[] args) {
        Employee e = new Employee("Ada", 1200000);
        Manager m = new Manager("Grace", 2400000, 600000);
        System.out.println(e.describe());
        System.out.println(m.describe());
    }
}

Manager never wrote a describe method; it inherited one. Yet for Grace, describe calls the Manager version of monthlyPay, because the object is a Manager. That's polymorphism, the subject of the next lesson.

@Override

@Override asks the compiler to check that you really are overriding a parent's method. Misspell the name, say speek(), and instead of silently creating a new method that nothing calls, the compiler reports an error. Always use it.

Every class extends Object

A class without extends still has a parent: Object, which supplies toString(), equals() and hashCode() to every class.

Java
class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "(" + x + ", " + y + ")";
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Point)) return false;
        Point p = (Point) other;
        return x == p.x && y == p.y;
    }

    @Override
    public int hashCode() {
        return 31 * x + y;
    }
}

public class Main {
    public static void main(String[] args) {
        Point a = new Point(2, 3);
        Point b = new Point(2, 3);
        System.out.println(a);              // (2, 3)
        System.out.println(a == b);         // false: different objects
        System.out.println(a.equals(b));    // true: equal values
    }
}

Object's own equals only checks whether two references are the same object. Override it to compare values, and always override hashCode alongside it, or HashMap and HashSet will misbehave with your class.

The rules

  • A class can extend only one class. (It can implement several interfaces, which come two lessons from now.)
  • A final class can't be extended at all; String is one.
  • A subclass can't see its parent's private members. protected makes a member visible to subclasses.

When to use inheritance

Use extends for a genuine "is a" relationship: a Manager is an Employee. When the relationship is "has a" (a Car has an Engine), give the class a field instead. That's called composition, and it's usually the more flexible choice.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.