Dennis Kriechel
Dennis Kriechel

Reputation: 3749

Variable is null at super call

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

Answers (4)

x7R5fQ
x7R5fQ

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

Akash Thakare
Akash Thakare

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

Juvanis
Juvanis

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

WoDoSc
WoDoSc

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

Related Questions