Heed these words of wisdom.
As a general rule in Java, never call a polymorphic method from a constructor. That is to say, never call a method that is neither static
nor final
, in the constructor of a class that is also not final
. Because of certain ordering issues with the default construction behaviours, you can quite easily find yourself in an apparently absurd situation which is hard to understand without a lot of thought.
Take the following classes as an example:
public class A { public A() { validate(); } protected void validate() { // Nothing to assert. Pass! } } public class B extends A { private final String blah = "blah"; private final String fwee; public B() { fwee = "fwee"; } @Override protected void validate() { if (!blah.equals("blah")) { throw new IllegalStateException(); } if (!fwee.equals("fwee")) { throw new IllegalStateException(); } // Otherwise pass! } }
Can you spot the problem? No? Neither did I, at first.
If you compile these classes [zipped source, compiled jar] and construct a new B()
you should receive a horrible NullPointerException
from the first line of B.validate()
. It turns out that when you execute a constructor such as B()
the following things happen, in this order:
super()
or this()
... in this case super()
blah = "blah"
fwee = "fwee"
Because super()
means A()
, and A()
calls validate()
, we find ourself attempting to execute blah.equals("blah")
before the default initialisation. So blah
is null
!
If you were a good (read: paranoid) programmer, you might have felt a bit nervous about assigning fwee = "fwee";
inside the constructor, since you probably realise that Java always calls another, more general, constructor (like super()
or this()
) at the start of every constructor — unless you explicitly call one yourself. But you, like I, may have been falsely comforted by the fact that both blah
and fwee
are explicitly final
. Well, such comfort is false comfort, it would seem.
I don't know how to define, let alone phrase, the proper rule so I'll stick with my gross generalisation. Follow this rule, and there's one more bizarre Java bug you won't have to waste half an hour debugging in future.
Never call a polymorphic method from a constructor.
... Matty /<