-1

Let's say we have a class:

public class MyClass extends AbstractClass {

    private AnotherObject ao = null;

    public MyClass() {
        super();
    }

    @Override
    protected void init() {
        ao = new AnotherObject();
        if (ao != null) {
            log.info("NOT NULL");
        }
    }

    @Override
    protected void doSomething() {
        if (ao == null) {
            log.info("It is NULL.");
        }
        ao.doIt(); //NullPointerException here
    }
}

And the corresponding abstract class:

public class AbstractClass implements Runnable {
    Thread myThread = null;
    
    AbstractClass () {
        init();
        myThread = new Thread(this, "ThreadName");
        myThread.start();
    }

    public void run() {
        while(true) {
            doSomething();
            Thread.sleep(1000);
        }
    }

    protected abstract void init();
    protected abstract void doSomething();
}

The constructor of MyClass calls the parent's constructor and the parent's constructor calls the init() method. This init method initializes the ao variable and therefore the log shows, that this ao object is NOT null.

After this, the parent's constructor creates a thread and this thread will execute the while loop, which calls doSomething(). In this overridden method, the ao object is used, but this ao object is suddenly null.

Can somebody explain me the ao object is set and then suddenly it is null?

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
Alex
  • 161
  • 1
  • 13
  • 4
    Not sure if that's the reason of this behaviour but passing a half-created object into another thread seems like terrible idea - you shouldn't pass `this` inside of a constructor. – Amongalen Aug 17 '20 at 08:47
  • 2
    @GokulNathKP no, this is not the problem here. This question is about understanding the initialisation of a class, not about the null, specifically. – Hulk Aug 17 '20 at 08:51
  • Also related: https://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors – Hulk Aug 17 '20 at 08:55

2 Answers2

10
private AnotherObject ao = null;

Remove the = null;.

You are initializing it by the methods invoked in the super constructor, but the initializer to null is then executed afterwards.

To be more clear, this:

    private AnotherObject ao = null;

    public MyClass() {
        super();
    }

is identical to this:

    private AnotherObject ao;

    public MyClass() {
        super();
        ao = null;
    }
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
2

According to here, the super constructor is run before the field initialisers (i.e. private AnotherObject ao = null;).

Therefore, the super(); call gets run, sets ao to non-null, returns, and then private AnotherObject ao = null; gets run, setting ao to null again.

This is why you should not call methods that can be overridden in subclasses in a constructor. Because at that point, this has not been fully initialised.

Sweeper
  • 213,210
  • 22
  • 193
  • 313