简体   繁体   中英

Inheritance, NullPointerException concept of super()

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM