Monday, 29 April 2019

Don't call non-final methods from constructors

You would expect the following program outputs 10.

public class ConstuctorTest {
    public static void main(String args[]) {
        Derived d = new Derived();
        System.out.println("From main() d.value() returns " + d.value());
    }
}

class Base {
    private int val;

    public Base() {
        val = lookup();
    }

    public int lookup() {
        return 5;
    }

    public int value() {
        return val;
    }
}

class Derived extends Base {
    
    private int num = 10;

    public Derived() {
        super();
    }
    
    public int lookup() {
        return num;
    }
}

The actual outcome, surprisingly, is:

From main() d.value() returns 0

Have a look at the order of statement execution.

public class ConstructorTest {
    public static void main(String args[]) {
        Derived d = new Derived();
        System.out.println("From main() d.value() returns " + d.value());
    }
}

class Base {
    private int val;

    public Base() {
        System.out.println("Base constructor"); // 1
        val = lookup();
    }

    public int lookup() {
        return 5;
    }

    public int value() {
        return val;
    }
}

class Derived extends Base {
    
    private int num = generateNum();

    public Derived() {
        super();
        System.out.println("Derived constructor num = " + num); // 4
    }
    
    private int generateNum() {
        System.out.println("Generate num"); // 3
        return 10;
    }
    
    public int lookup() {
        System.out.println("Look up num: "+num); // 2
        return num;
    }
}

Output:
Base constructor
Look up num: 0
Generate num
Derived constructor num = 10
From main() d.value() returns 0

It turns out the assignment of instance variable happens after the calling of the constructor of the super class, and before the very first statement of the constructor of this class.

The lesson is if you want to call an instance method in the constructor, you should declare the method as final.

No comments:

Post a Comment