Skip to content
Educora
Intermediate17 min8 / 18

Inheritance and polymorphism

Extend an existing class with extends, use super and @Override, and learn how polymorphism and instanceof work.

Check yourself
In this lesson you will learn
  • Create a subclass with extends and super
  • Override a method with @Override
  • Explain polymorphism and check a type with instanceof

A company has ordinary employees and managers. Both have a name and a salary, but a manager also gets a bonus. Instead of writing a Manager class from scratch and repeating all of Employee's code, we can say: “A manager is an employee too, just a little different.” That is what inheritance is for.

extends and super

Writing class Manager extends Employee says that Manager inherits from Employee: the subclass receives the fields and methods of the superclass. A subclass constructor must first call the parent's constructor with super(...). And super.salary() calls the parent class's version of a method.

Java
public class Main {
    public static void main(String[] args) {
        Employee e = new Employee("Nigar", 1200);
        Manager m = new Manager("Rashad", 2000, 500);
        System.out.println(e.describe());
        System.out.println(m.describe());
        System.out.println(m.getName() + " earns " + m.salary());
    }
}

class Employee {
    protected String name;
    protected double baseSalary;

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

    String getName() { return name; }

    double salary() { return baseSalary; }

    String describe() {
        return name + ": " + salary() + " AZN";
    }
}

class Manager extends Employee {
    private double bonus;

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

    @Override
    double salary() {
        return super.salary() + bonus;
    }
}
Expected output
Nigar: 1200.0 AZN
Rashad: 2500.0 AZN
Rashad earns 2500.0
  • Manager does not define getName() or describe(), yet they work — they are inherited from the parent.
  • The salary() method is overridden: same name and parameters, but new behaviour.
  • Notice: describe() is written in the parent, but for the manager it showed 2500. When it calls salary(), the version from the object's actual class runs.
  • protected fields are visible to subclasses but not to outside code (from other packages).

Polymorphism

Polymorphism (“many forms”) means that a variable of a parent type can refer to an object of any subclass, and when a method is called, the version from the object's actual class runs. Below, a Shape array holds circles and rectangles, and the loop calls area() without caring which is which — each shape calculates its area in its own way.

Java
public class Main {
    static double round2(double x) {
        return Math.round(x * 100) / 100.0;
    }

    public static void main(String[] args) {
        Shape[] shapes = { new Circle(1), new Rectangle(3, 4), new Circle(2) };
        double total = 0;
        for (Shape s : shapes) {
            System.out.println(s.name() + ": " + round2(s.area()));
            total += s.area();
        }
        System.out.println("Total: " + round2(total));
    }
}

class Shape {
    String name() { return "Shape"; }
    double area() { return 0; }
}

class Circle extends Shape {
    private double r;
    Circle(double r) { this.r = r; }
    @Override String name() { return "Circle"; }
    @Override double area() { return Math.PI * r * r; }
}

class Rectangle extends Shape {
    private double w, h;
    Rectangle(double w, double h) { this.w = w; this.h = h; }
    @Override String name() { return "Rectangle"; }
    @Override double area() { return w * h; }
}
Expected output
Circle: 3.14
Rectangle: 12.0
Circle: 12.57
Total: 27.71
Interactive
Loading simulation…
Change the circle's radius and compare the area with the formula in the Circle class — π · r². Pick the other shapes too: each of them could become its own subclass.

The power of polymorphism is that if you add a Triangle class tomorrow, the loop in main will not need to change at all. The code depends on the general type (Shape), not on the specific classes. This is how large programs grow.

Checking types with instanceof

Sometimes you need to know an object's specific type. The expression o instanceof String s checks whether o is a String and, if it is, puts it straight into a String variable named s. This form (pattern matching) has been available since Java 16.

Java
public class Main {
    public static void main(String[] args) {
        Object[] things = { "Baku", 42, new Dog("Rex"), 3.5 };
        for (Object o : things) {
            if (o instanceof String s) {
                System.out.println("String of length " + s.length());
            } else if (o instanceof Dog d) {
                d.bark();
            } else {
                System.out.println("Something else: " + o);
            }
        }
    }
}

class Dog {
    private String name;
    Dog(String name) { this.name = name; }
    void bark() { System.out.println(name + " says Woof!"); }
}
Expected output
String of length 4
Something else: 42
Rex says Woof!
Something else: 3.5

Key points

  • class B extends A — B inherits A's fields and methods; in Java a class can extend only one class.
  • super(...) calls the parent's constructor, and super.method() calls the parent's method.
  • @Override makes the compiler check that a method really replaces a parent method.
  • Polymorphism: a parent-type variable refers to a subclass object, and the method of the object's actual class runs.
  • o instanceof Type t checks the type and immediately gives you the object in a new variable.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
How do you call the parent's constructor from a subclass constructor?