23

I have a abstract class and a derived class. Look at provided code:-

public abstract class Parent{
    public Parent(){
        init();
    }

    public abstract void init();    
}



public class Child extends Parent{
    private String mTitle = null;

    public Child(){
        super();
        System.out.println(mTitle.toString());
    }       

    public void init(){
        mTitle = "It' a test";
    }    
}

When I will execute the above code it will throw NullPointerException on printing the value of mTitle. If you check the code in constructor of parent I have called the the abstract method which will called the init method of derived class, In abstract method I have initialize the value of mTitle value as ="It's a test";

After calling parent constructor derived class have to call the System.out.println.

If it is doing in that way then why it is throwing NullPointerException.

But, If I just leave the assignment of mTitle it will not throw Exception like:-

private String mTitle;

If initialization of variable occur on calling of the contruct of class and we know by default global object have initialize to null. But in this case it will not throw Exception.

VikasGoyal
  • 3,308
  • 1
  • 22
  • 42
  • 1
    @1owk3y a typo, obviously. This wouldn't even compile with `extenda`, much less throw a `NullPointerException` at runtime. – toniedzwiedz Nov 09 '14 at 10:40
  • 1
    Also, "Public" is not a legal keyword when defining a class. Also, `init():` isn't a legal statement, you probably want a `;` there. Please double check that the code you posted is actually the code you are running. Your numerous typos raise some doubts on that. – azurefrog Nov 09 '14 at 10:40
  • 7
    You're calling an overridable method in a constructor. This can yield unexpected behaviour and shouldn't be done. Further reading: http://stackoverflow.com/q/3404301/1407656 – toniedzwiedz Nov 09 '14 at 10:42
  • But, if I will not assign the value of mTitle in class and simply write it like:- private String mTitle; It will not throw Exception. – VikasGoyal Nov 09 '14 at 10:55

3 Answers3

26

As in JLS §12.5 (Creation of New Class Instances) the following procedure is used when an instance is created:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

  2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

  5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

That means your call to super() and the subsequent call to the overridden init() method are both done before the instance variable is initialized with null which discards the outcome of the init method and overwrites any value being assigned to mTitle with the null value.

This leads to the following Golden Rule: Never call non-final, non-private methods in a constructor!

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
13

According to Section 12.5 of the JLS, the superclass constructor will run before the initialiser for mTitle, which means that it will be set back to null after it is set to "It's a test".

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
0

According to section 12.5 of the JLS, the superclass constructor will run before the constructor of derived class.

The initalization of global variable is call at the time of calling of constuctor. So when super class constructor call the abstract method and set the mTitle value in abstarct method implementation it will set the first it's value to ="it's a test". After finishing super class constructor it will call derived class constructor and when derived class constructor call it will first initalize its global variable which set mTitle value to the null. As it is mention in code

private String mTitle = null;

But in second case mTitle have not assign any value in code as mention

private String mTitle;

so it will take its default value which is we assigned in implemented of abstarct method init "it a test " so it will not produce any Exception.

VikasGoyal
  • 3,308
  • 1
  • 22
  • 42