I ran into an interesting problem yesterday and while the fix was quite simple, I'm still a bit fuzzy on the "why" of it.
I have a class that has a private member variable that is assigned when it is instantiated, however if it is used in an abstract function that is called by the super class's constructor, the variable does not have a value. The solution to the problem was quite simple, I simply had to declare the variable as static and it was assigned correctly. Some code to illustrate the problem:
class Foo extends BaseClass
{
private final String bar = "fooBar!";
public Foo()
{
super();
}
@Override
public void initialize()
{
System.out.println(bar);
}
}
And the base class:
abstract class BaseClass
{
public BaseClass()
{
initialize();
}
public abstract void initialize();
}
In this example, when we call new Foo();
it will output (null) instead of the expected fooBar!
Since we're instantiated an object of type Foo, should its members not be allocated and assigned prior to calling its (and consequently its super class's) constructor? Is this specified somewhere in the Java language or is it JVM specific?
Thanks for any insight!
A constructor is typically used to initialize instance variables representing the main properties of the created object. If we don't supply a constructor explicitly, the compiler will create a default constructor which has no arguments and just allocates memory for the object.
There's a way to get some code (other constructors) to run before the constructor really starts, before any members of the subclass are initialized. And that way is to put the "call" (eg super ) on the very first line.
Variable initialization is important so that we do not accidently use a variable without assigning a value to it. Similarly Object initialization is important so that we do not accidently use an object before initializing the data members of the object.
Why creating an object of the sub class invokes also the constructor of the super class? When inheriting from another class, super() has to be called first in the constructor. If not, the compiler will insert that call. This is why super constructor is also invoked when a Sub object is created.
The assignment of bar = "fooBar!";
is inlined into the constructor during compile time.
The superclass constructor runs before the subclass constructor, hence it would only be natural that the statement is executed afterwards.
Generally though, it's bad practice to call overridable methods from a constructor.
It is as defined by the Java Language Specification. Changing it to static will almost never be and acceptable solution in real world situation.
See JLS 4.12.5 Initial Values of Variablesand JLS 8.3.2 Initialization of Fields
Overall, it is bad practice to call a non-final method from a constructor. the reason being that it could (and if the method is abstract then definitely does) call method in the class that has not yet been initialized: When new Foo()
is executed, the BaseClass
initializer (constructor) gets called before the Foo
constructor, so Foo.initialize
is essentially working on an Object that has not been fully constructed yet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With