1

There's a base class ServerAdapter:

public abstract class ServerAdapter {
    public ServerAdapter() {
        initGUI();
    }

    protected abstract void initGUI();
}

And a child class that inherits ServerAdapter:

public abstract class LinuxServerAdapter extends ServerAdapter {
    protected CheckBox key = new CheckBox();

    public LinuxServerAdapter() {
        super();
    }

    @Override
    public void initGUI() {
        //NPE is thrown here, because key = null
        key.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                //Something happens here
            }
        });
    }
}

End class that inherits LinuxServerAdapter:

public class MyLinuxServerAdapter extends LinuxServerAdapter {

    public MyLinuxServerAdapter() {
        super();
    }

    public static void main(String args[]) {
        ServerAdapter server = new MyLinuxServerAdapter();
    }
}

NPE is thrown when I try to add clickHandler on a key.

Why key isn't initialized? Is this a case where initialization order works in a specific way?

Dragon
  • 2,431
  • 11
  • 42
  • 68
  • 1
    Initialization order *always* works in a specific way, and that way is detailed in the JLS. It's one reason why calling down into subclasses during construction can be^H^H^H^H^H^His sketchy. – Dave Newton May 23 '13 at 13:57
  • 1
    http://stackoverflow.com/questions/10589828/java-constructor-and-field-initialization-order – dugas May 23 '13 at 13:57
  • My guess is that `initGUI()` is called from a base class. Your class text is _essentially_ appended to the end of base class in invocation order. – Jesan Fafon May 23 '13 at 13:58
  • 1
    @JesanFafon You don't have to guess, it's there on line three. – Dave Newton May 23 '13 at 13:59
  • Oh, I understood. At first, base class initialization takes place and when we call a method implemented in a subclass, we don't call a c-tor of this subclass at the moment. Hm. – Dragon May 23 '13 at 14:01

2 Answers2

5

Just initialize in the init method. That's the purpose after all..

@Override
public void initGUI() {
    key = new CheckBox();
    key.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            //Something happens here
        }
    });

The parents classes gets instantiated before the children. In your top parent class you call the initGUI() abstract method, which its implementation is located in its child that doesn't not yet have its other fields initialized. It makes sense to move the actual initialization of the field to the initGUI() method, it fits the name convention and the logic of what you got.

Sednus
  • 2,095
  • 1
  • 18
  • 35
  • So the only way to avoid it is to move all fields initialization to initGUI implementation? – Dragon May 23 '13 at 13:59
  • Its not the only but its the simpler. – Sednus May 23 '13 at 14:01
  • What are the other variants if it isn't a secret? :) But anyway your variant is good for me. – Dragon May 23 '13 at 14:09
  • Another possible workaround would have been to make the checkbox static. But that could arise other issues since it would be a shared filed between all instances – Sednus May 23 '13 at 14:50
  • Another would be to move the initGUI call to the class that has the implementation of it (LinuxServerAdapter). But I believe you want to enforce the call from a higher level, which make sense. – Sednus May 23 '13 at 15:17
1

Assignments in the declaration of instance variables, and any statements in non-static blocks within the class block, are run after the super() call has returned. If you call a method of the subclass from the superclass's constructor, it will be using the uninitialized this.

This is why there is a general rule that you should never call a virtual method from a constructor.

Russell Zahniser
  • 16,188
  • 39
  • 30
  • So the other way to do it (in order to avoid rule violation) is just to call virtual method from a subclass c-tor? – Dragon May 23 '13 at 14:04