0

Base Class:

public class Base {
    private String baseMessage = "Hello!";

    public Base() {
        printMessage();
    }

    public void printMessage() {
        System.out.println(baseMessage.toString());
    }
}

Derived Class:

public class Derived extends Base {
    private String derivedMessage = "World!";

    public Derived () {
        super();

    }

    @Override
    public void printMessage() {
        super.printMessage();
        System.out.println(derivedMessage.toString());
    }


    public static void main(String[] args) {
//      new Base();
        new Derived();
    }
}

When I run

new Base();

I get the expected output:

Hello!

When I Run

new Derived();

I get

Hello!
Hello!

then NullPointerException. This seems a bit weird to me. I don't know why it's printing it out then throwing a nullpointerexception, rather straight up throwing it. Maybe it's Eclipse, I don't know.

What's the underlying concept here?

user121449
  • 15
  • 2

1 Answers1

5

Before you read this, read

The body of a child class constructor is compiled to something like this

public Derived () {
    super();
    initializeInstanceFields(); 
    // all instance fields are initialized either to their default value
    // or with their initialization expression
}

In other words, by the time the Derived#printMessage() is called because of polymorphism from the super constructor, the Derived.derivedMessage is still null.


Here's the step by step:

new Derived();

invokes the Derived constructor

public Derived () {
    super();
}

which invokes the super constructor

public Base() {
    printMessage();
}

Here, before the printMessage(), this class' instance fields are initialized, so baseMessage gets the value of "Hello!". When printMessage() gets invoked, because this is a Derived object and Derived overrides the methods, its implementation is invoked.

@Override
public void printMessage() {
    super.printMessage();
    System.out.println(derivedMessage.toString());
}

This calls the super implementation

public void printMessage() {
    System.out.println(baseMessage.toString());
}

which prints

Hellow!

The method returns back to Derived#printMessage and attempts to invoke toString() on derivedMessaged, but, as I've explained earlier, the derivedMessage hasn't been initialized yet, so it is null. Dereferencing null causes NullPointerException.

And this is why you don't invoke overridable methods from constructors.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • super() gets called, then it initializes all the fields?. How about the parent class? Does the fields get initialized there when super() is called, then derived class's fields get initialized? – user121449 Apr 16 '14 at 02:59
  • @user121449 The `Base` class has its own call to `super()` (which invokes the `Object` constructor) and then initializes its own fields. – Sotirios Delimanolis Apr 16 '14 at 03:00
  • Second-question: why would Hello! get printed twice? – user121449 Apr 16 '14 at 03:01
  • @user121449 It shouldn't. Save your code, recompile, and try again. – Sotirios Delimanolis Apr 16 '14 at 03:01
  • I think it's running the function from the base class twice, then going to the derived? But that doesn't make sense, since I never explicitly call the derived function – user121449 Apr 16 '14 at 03:04
  • Because you override the printMessage() function it is then being called when the Base() constructor is being called. – Eddie Curtis Apr 16 '14 at 03:05
  • @user121449 Are you sure you're not just seeing the output from `new Base()` from before? There should be only one `Hello!` printed for `new Derived();`. – Sotirios Delimanolis Apr 16 '14 at 03:05
  • @user121449 maybe you haven't commented out `new Base();`. That's why you are seeing `Hello!` printed twice. – anonymous Apr 16 '14 at 03:06