What's wrong with overridable method calls in constructors?

I have a Wicket page class that sets the page title depending on the result of an abstract method.

public abstract class BasicPage extends WebPage {

    public BasicPage() {
            add(new Label("title", getTitle()));
    }

    protected abstract String getTitle();

}
NetBeans warns me with the message “Overridable method call in constructor”, but what should be wrong with it? The only alternative I can imagine is to pass the results of otherwise abstract methods to the super constructor in subclasses. But that could be hard to read with many parameters.

On invoking overridable method from constructors

Simply put, this is wrong because it unnecessarily opens up possibilities to MANY bugs. When the @Override is invoked, the state of the object may be inconsistent and/or incomplete.

 

A quote from Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:

 

There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will be invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.

 

Here's an example to illustrate:

 

public class ConstructorCallsOverride {

    public static void main(String[] args) {

        abstract class Base {

            Base() { overrideMe(); }

            abstract void overrideMe(); 

        }

        class Child extends Base {

            final int x;

            Child(int x) { this.x = x; }

            @Override void overrideMe() {

                System.out.println(x);

            }

        }

        new Child(42); // prints "0"

    }

}

Here, when Base constructor calls overrideMe, Child has not finished initializing the final int x, and the method gets the wrong value. This will almost certainly lead to bugs and errors.