Reputation: 2311
I have a simple Java Program:
public abstract class Test {
public Test() {
foo();
}
public abstract void foo();
}
public class Test2 extends Test {
private final Object testObj = new Object();
public Test2() {
super();
}
@Override
public void foo() {
System.out.println("object is: " + testObj);
}
}
When instantiating Test2
its contructor calls the constructor of Test
, which in turn calls the method foo
implemented in Test2
during execution of foo
, the field testObj
is null
, even though it is final.
Is this the correct behaviour? If so, is there a pattern to work around it?
Upvotes: 1
Views: 85
Reputation: 265
Even if you don't put super() method in the constructor of base class. Compiler will place super() method itself. Eg:
class A {
A() {
System.out.println("A");
}
}
class B extends A {
B() {
System.out.println("B");
}
}
class C extends B {
C() {
System.out.println("C");
}
public static void main(String[] args) {
C c = new C();
}
}
You can recheck above function by placing super() method in first line of each constructor. Workflow will not change. There is also another rule that super() and this() method will always be placed only in first line of the constructor. This is the workflow of java in case of inheritance.
Now come to your question. When you are creating instance of Test2, super() method is called from the constructor before initialization of testobj. Hence, when foo() method is called from base class Test, testobj wast not initialized and function was called that's why it is showing null.
Upvotes: 0
Reputation: 3563
You are calling a Test2
method while Test2
hasn't finished construction yet, only the Test
part of the object is finished. Therefore instance variables of Test2
are not assigned yet (thankfully they are null
and not some random memory pointer !)
The 'correct' pattern would be to not call a abstract method in the base classes' constructor, and if you really need to not to have that method being dependent on its instance variables, but only on parameters.
Upvotes: 0
Reputation: 726599
Yes, this is the correct behavior: testObj
of the derived class gets initialized only after the superclass has finished initializing; since foo()
is called before the initialization of the superclass has finished, testObj
remains null
.
The best work-around to this problem is to not call abstract methods inside a constructor, because they may find their object in uninitialized state. Another alternative is to postpone the call to foo()
. If foo
must be called as part of initialization sequence because it provides something to the base class, it should not access any state on the instance.
Upvotes: 2