I recently spent quite a few minutes debugging a problem in production code that in the end turned out to be caused by a class calling an abstract method in its constructor, and the subclass implementation of that method tried to use a subclass field that had not been initialized yet (An example that illustrates the point is included below)
While researching this, I stumbled across this question, and was intrigued by Jon Skeet’s answer:
In general it’s a bad idea to call a non-final method within a constructor for precisely this reason – the subclass constructor body won’t have been executed yet, so you’re effectively calling a method in an environment which hasn’t been fully initialized.
This has me wondering, is there ever a legitimate reason to call a non-final or abstract method from a constructor? Or is it pretty much always a sign of bad design?
Example
public class SSCCE {
static abstract class A {
public A() {
method(); // Not good; field arr in B will be null at this point!
}
abstract void method();
}
static class B extends A {
final String[] arr = new String[] { "foo", "bar" };
public B() {
super();
System.out.println("In B(): " + Arrays.toString(arr));
}
void method() {
System.out.println("In method(): " + Arrays.toString(arr));
}
}
public static void main(String[] args) {
new B().method();
}
}
And here is expected output:
In method(): null
In B(): [foo, bar]
In method(): [foo, bar]
The problem, of course, is that in the first call to method() the field arr is null because it hasn’t been initialized yet.
There are times it can be very hard not to.
Take Joda Time, for example. Its
Chronologytype hierarchy is very deep, but the abstractAssembledChronologyclass is based on the idea that you assemble a bunch of “fields” (month-of-year etc). There’s a non-final method,assembleFields, which is called during the constructor, in order to assemble the fields for that instance.They can’t be passed up the constructor chain, because some of the fields need to refer back to the chronology which creates them, later on – and you can’t use
thisin a chained constructor argument.I’ve gone to nasty lengths in Noda Time to avoid it actually being a virtual method call – but it’s something remarkably similar, to be honest.
It’s a good idea to avoid this sort of thing if you possibly can… but sometimes it’s a real pain in the neck to do so, especially if you want your type to be immutable after construction.