Reputation: 3749
I'm using Java 7 and got 3 classes:
TestSuper.java
public abstract class TestSuper {
public TestSuper() {
testMethod();
}
protected abstract void testMethod();
}
TestNull.java
public class TestNull extends TestSuper {
private String test = "Test";
public TestNull() {
super();
System.out.println(test);
}
@Override
protected void testMethod() {
System.out.println(test);
}
}
TestMain.java
public class TestMain {
public static void main(String[] args) {
new TestNull();
}
}
Output:
null
Test
Why does this happen and is there a good workaround for it?
Upvotes: 5
Views: 2968
Reputation: 1029
you can work around this issue by moving the call of testMethod()
to a separate function
public abstract class TestSuper {
public TestSuper() { }
public void callTestMethod(){
testMethod();
}
protected abstract void testMethod();
}
then call callTestMethod()
on TestNull
constructor
public TestNull() {
super.callTestMethod();
System.out.println(test);
}
Upvotes: 0
Reputation: 23002
According to JLS 8.1.1.1 Abstract Class
A subclass of an abstract class that is not itself abstract may be instantiated, resulting in the execution of a constructor for the abstract class and, Therefore, the execution of the Field Initializers for instance variables of that class.
Upvotes: 2
Reputation: 25950
You are calling an overridable instance method (which also calls an instance field, in your case private String test = "Test";
) in the constructor. This might cause inconsistencies since the instance is not fully constructed. This is a bad practice, so avoid it:
public TestSuper() {
testMethod();
}
Please read this thread: What's wrong with overridable method calls in constructors?
Upvotes: 1
Reputation: 2618
When you call new TestNull();
you're calling the constructor of the class TestNull
, which it calls the super()
constructor: it contains a call to the method implemented in TestNull
, where you print the String field, at this time the fields of the sub-class TestNull
are not yet initialized, i.e. are null.
After the super constructor call, all the fields will be initialized, and therefore the second print actually show the new value of the (initialized) string.
The key point here is that fields of a sub-class are initialized after the instantiation of the super-classes.
A workaround? It depends on what exact behaviour you desire: maybe it makes sense to NOT call the abstract method in the super constructor (i.e. in the constructor of the TestSuper
class).
Upvotes: 8