Skip to content
CodeKruPro

Predict the output · Java

Classes, static members and inheritance

Overriding, hiding, constructors order and shared state.

Learn: Overriding, hiding and init order in Java7 minute read

Class questions show a parent class, a child class and a few calls, and ask what prints. They test object-oriented basics that every automation framework uses: a base test class, page classes that extend a base page, overridden setup methods. One idea answers most of them: some choices are made at run time (while the program runs) from the actual object, and others at compile time (before it runs) from the declared type of the variable. Add the order in which classes and objects are built, and you can answer almost any of them.

Two words first

In Shape s = new Circle();, the declared type of s is Shape and the actual object is a Circle. Overriding means a child class writes a method with the same name and parameters as a parent method (the name plus the parameter types is called the signature). Overloading means one class has several methods with the same name but different parameters.

Rule 1: instance methods are chosen at run time

When you call an instance method, Java looks at the class of the actual object, not the declared type. A Shape variable that holds a Circle runs Circle's override. This is dynamic dispatch, or runtime polymorphism (the same call runs different code depending on the object). It also applies to calls made from inside the parent class: this.describe() in Shape still runs the child version.

Rule 2: fields, static methods and overloads are chosen at compile time

Fields are never overridden. If a child declares a field with the same name, the object has two fields, and the declared type of the variable decides which one you read. Static methods are not overridden either; a child static method with the same signature hides the parent one, and the declared type decides which runs. Private methods are not inherited, so they are not overridden.

Overloading is also decided at compile time, from the declared types of the arguments. An Object variable holding a string picks the Object overload, and null picks the most specific one that fits. A common bug is writing equals(MyType other): it overloads instead of overriding equals(Object), so collections never call it. @Override catches that at compile time.

class Shape {
    String name = "shape";

    static String kind() {
        return "Shape.kind";
    }

    String describe() {
        return "a shape";
    }
}

class Circle extends Shape {
    String name = "circle";

    static String kind() {
        return "Circle.kind";
    }

    @Override
    String describe() {
        return "a circle";
    }
}

public class Main {
    public static void main(String[] args) {
        Shape s = new Circle();
        System.out.println(s.describe());
        System.out.println(s.name);
        System.out.println(s.kind());
    }
}
a circle
shape
Shape.kind

Rule 3: the order of initialisation

  1. A class is initialised once, the first time it is used. Its static fields and static blocks (code written in static { ... }) run then, in the order written, and a parent class is initialised before its child.
  2. Each new runs the constructor chain from the top: every constructor first calls its parent constructor (the compiler adds super() when you do not write one). A constructor that starts with this(...) passes that job to the other constructor.
  3. After the parent constructor returns, the class's instance field initialisers (the = value part of a field) and instance blocks (code in plain { ... } inside the class, run for every new object) run in the order written, then the rest of the constructor body.
class Parent {
    static {
        System.out.println("Parent static");
    }

    Parent() {
        System.out.println("Parent constructor");
    }
}

class Child extends Parent {
    static {
        System.out.println("Child static");
    }

    {
        System.out.println("Child instance block");
    }

    Child() {
        System.out.println("Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
        new Child();
    }
}
Parent static
Child static
Parent constructor
Child instance block
Child constructor
Parent constructor
Child instance block
Child constructor

Rule 4: overridable calls from a constructor see default values

The parent constructor runs before the child's fields get their values. So an overridden method called from the parent constructor sees the child's fields at their defaults: 0, false or null. This is a classic hard question and a real source of bugs.

Rule 5: static members are shared

A static field exists once per class, however many objects there are. Every object that changes it changes the same value.

How to answer in an interview

Start by naming the declared type and the actual object, then say which rule applies. "describe is an instance method, so the object decides: a circle. name is a field, so the declared type decides: shape." For init order, number the steps out loud. Interviewers often follow up with "where does your framework use this?": a base test class whose setup method a child overrides is a good example.

Common mistakes

  • Expecting fields or static methods to behave polymorphically.
  • Choosing an overload from the object instead of the declared type.
  • Running static blocks again for every new object.
  • Running the child constructor body before the parent constructor.
  • Forgetting that child fields are still at defaults during the parent constructor.

Recap

Overridden instance methods follow the actual object; fields, static methods and overloads follow the declared type. Classes initialise once, parent first. Objects build from the top of the constructor chain down, with instance blocks after super().

10 questions0/10 solved

StatusQuestionDifficultyAsked in
Not startedA parent reference to a child objectEasyAsked in: Cognizant, Wissen Technology
Not startedA static counter shared by all objectsEasyAsked in: Infosys
Pro+Constructor order in a class chainEasy-Medium
Pro+super.method() and this(...) togetherMediumAsked in: Capgemini
Pro+Static blocks, instance blocks and constructorsMediumAsked in: Capgemini, IBM, Infosys
Pro+Static methods are hidden, not overriddenMediumAsked in: Capgemini
Pro+Fields are not polymorphicMedium
Pro+Overloading is decided by the declared typeMedium-Hard
Pro+An overridden method called from a parent constructorHard
Pro+equals(Point) overloads instead of overridingHard
Not startedNot startedIn progressIn progressSolvedSolvedPro+Pro+

The first 2 questions of each topic are free. Pro+ opens every question.

Back to the plan