What’s wrong with calling Overridable method in constructor?

This is the follow-up post of my answer on – this Stack Overflow question. Basically the question goes like this:

The application is doing this when creating an instance of the class B using a load class by name method.

  • Calls overridden load() in class B, from A class constructor ( B extends A)
  • Initializes variables (calls “private string testString = null” according to debugger), nulling them out

The major issue with the code in that post is, the non-final base class (A) constructor invokes a non-final method, which is overridden in the derived class (B). Due to this, the code will behave unexpectedly. I’ll explain the issue in detail in the following post. But first of all, you should understand (if you not already do) what happens behind the scene, when you create an object of a class. For that, I suggest you to go through my last post – Object creation process: Inheritance. If you already know about the process, you can proceed further.

When a method of a class is called, it expects that the instance on which it is called is completely initialized, so that it can work freely on the data (fields) of that class. Now,  as explained in my last post (that I linked), when you create an instance of a class, first of all, all it’s super class members are initialized, then at the end, it’s own constructor executes further to initialize it’s own member fields. So, when an overridden method is called from the base class constructor, it will invoke the overridden version in derived class, rather than the base class. But at that point, the members of the derived class has not been initialized yet for the current instance (as super class constructor is not finished yet). That can cause trouble if that method is using the instance fields. Let’s understand it with the help of an example:

Code Talks Better: –

abstract class Operation {

    public Operation() {
        divide();
    }
    abstract int divide();
}

class Division extends Operation {

    private int numerator = 0;
    private int denominator = 0;

    public Division(int numerator, int denominator) {
        super();
        this.numerator = numerator;
        this.denominator = denominator;
    }

    int divide() {
        return numerator / denominator;
    }
}

Now from the main method, we create an instance of Division class:

public static void main(String... args) {
    Operation division = new Division(4, 2);
}

When you run the code, you shouldn’t be surprised on seeing the output:

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Division.divide(Main.java:75)
	at Operation.(Main.java:58)
	at Division.(Main.java:69)
	at Main.main(Main.java:84)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:491)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

So, what do you think have happened? Basically, when the “Operation” class constructor invoked the “divide()” method, it overridden method in “Division” class is called. At that point, since the “numerator” and “denominator” are not yet initialized by the “Division” class constructor, they will have their default value 0. And thus you got “/ by zero” exception, as “denominator” is 0.

So, the moral of the post is: –

  • Never invoke a non-final method of a non-final class inside it’s constructor. That method might have been overridden in one of it’s derived class, which might use the fields, which hasn’t been initialized yet.
Advertisements