Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Learn › Java › Classes and objects

Inheritance and overriding

When does the superclass constructor run when a subclass object is created?

A single object of a subclass contains both the fields inherited from the superclass and the fields that the subclass declares. When you use new, the superclass constructor finishes first, and only then do the field initializers and the constructor body of the subclass run. Because of this order, there are cases in which you must write super(...), and when the superclass constructor calls an overridden method, that method sees subclass fields that are still empty.

Checked against real execution · All 36 combinations were compiled and run on JDK 21, and the compilation result and the output were checked against the results

Concepts in this lab

Inheritance
This means defining a new class (the subclass) that receives the fields and methods of an existing class (the superclass). It reuses common code, and the subclass adds or overrides only the parts it needs. A Java class supports single inheritance only, and a change to the superclass affects every subclass, so it is best used only when there is a clear "is-a" relationship.
Overriding
This means that a subclass redefines a method of its superclass (or of an interface) with the same signature. At run time, the method that matches the type of the actual object is called, and this is how polymorphism is implemented. The access level cannot be made narrower, and static, private, and final methods cannot be overridden.
Constructor
This is code that runs once when an object is created with new and puts the fields into their initial state. Its name is the same as the class name, and it has no return type. A class can have several of them as long as they take different arguments, and the one that matches the arguments passed to new is selected. Its body runs after the fields have been set to their default values and the field initializers and initializer blocks have run.
super
This keyword refers, inside a subclass, to things that belong to the superclass. Writing super(arguments) as the first statement of a constructor calls the superclass constructor that matches those arguments, and if you do not write it, the compiler automatically inserts super() with no arguments. So when the superclass has no no-argument constructor, you must write super(arguments) yourself in the subclass constructor, and not writing it is a compile-time error. Writing super.method() inside a method calls the overridden method of the superclass.
Default values of fields
These are the values that are automatically placed in the fields that are not given a value when an object is created. Numeric types such as int get 0, boolean gets false, and reference types such as String get null. These values are what you see until a field initializer or a constructor assigns a value. Local variables inside a method have no default value, so reading one without assigning a value to it is a compile-time error.

Try these

Running with the default settings

  1. Compilation: The compiler looks at the first line of the constructor Dog(). super("Buddy") means that the superclass constructor Animal(String name), which takes one string, will be called. Animal has this constructor, so the code compiles.
  2. new Dog() runs: Memory for one Dog object is allocated on the heap. This object contains both name, inherited from Animal, and sound, declared by Dog, and both are set to their default value, null.
  3. The first line of the constructor Dog(), super("Buddy"): Before the field initializer and the constructor body of Dog run, control first passes to the superclass constructor, Animal(String name). This is because the inherited part must be ready first for the subclass to be able to use it.
  4. this.name = name in the body of Animal(String name): The "Buddy" that was passed in is assigned to name. sound is still null.
  5. System.out.println("Animal(String) runs"): The body of the superclass constructor is running. Not a single line of the body of the Dog() constructor has run yet.
  6. Animal(String name) calls describe() in its body: Which describe() runs is determined by the type of the actual object that is being created now. The actual object is a Dog, so the describe() that Dog overrides runs, even though the call is made inside the superclass constructor.
  7. println("sound=" + sound) inside describe() in Dog: The field initializer of Dog, sound = "Woof", runs only after the superclass constructor finishes. Right now sound has its default value, null, so the output is sound=null.
  8. The field initializer of Dog, String sound = "Woof": The superclass constructor has finished, and control is back in Dog(). Only now does the field initializer of Dog run, and sound is set to "Woof".
  9. System.out.println("Dog() runs"): The body of the Dog() constructor runs. The body of the subclass constructor comes last of all.
  10. Dog d = new Dog(): All the constructors have finished. The reference to the completed object is stored in the variable d.
  11. Called through d.describe(), println("sound=" + sound) inside describe() in Dog: The object has been fully created by now, so sound holds "Woof". The output is sound=Woof.

Result of this run

Code

class Animal {
    String name;

    Animal(String name) {
        this.name = name;
        System.out.println("Animal(String) runs");
        describe();                // calls an overridden method from the constructor
    }

    void describe() {
        System.out.println("name=" + name);
    }
}

class Dog extends Animal {
    String sound = "Woof";

    Dog() {
        super("Buddy");            // calls Animal(String) of the superclass
        System.out.println("Dog() runs");
    }

    @Override
    void describe() {
        System.out.println("sound=" + sound);
    }
}

Dog d = new Dog();
d.describe();

Assumptions of this model

All 36 combinations were actually compiled and run with the same code on JDK 21 on this PC, and the compilation result, the error message, the output while the object is being created, and the output of d.describe() were checked against the results. It was also confirmed by compiling that the same error occurs when the subclass declares no constructor and the superclass has no no-argument constructor, and that super(...) must be the first statement of a constructor (as of JDK 21). In newer JDKs this is said to have changed so that some statements can come before super(...), but this was not verified on this PC. Simplifications: the constructor of Animal also calls the constructor of its own superclass, Object, before anything else, and this step is left out. The detailed rules for which method is selected are covered in the "Polymorphism and method selection" lab. The error message is the first line of the English message from javac.

Previous lab: static and instance · Next lab: Polymorphism and method selection

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these