2

I am facing a problem with the below program , it has two classes A and B and one method getObject() in Class A that has been overridden in class B, Class B extends Class A.

I am calling getObject() from the base class constructor which I believe it will call the overridden method in class B, and at runtime the error is null pointer exception, why the Object has not been initialized, even so it has?

class A {
    Object object = new Object();

    public A() {
        System.out.println("A Class");
        getObject();
    }

    public void getObject() {
        System.out.println("Class A Version");
        System.out.println(object.toString());
    }
}

class B extends A {

    Object object = new Object();

    public B() {
        System.out.println("B Class");
    }

    @Override
    public void getObject() {
        System.out.println("Class B Version");
        System.out.println(object.toString());
    }
}

public class Init {
    public static void main(String[] args) {
        new B();
    }
}

output

A Class
Exception in thread "main" Class B Version
java.lang.NullPointerException
    at net.mindview.util.B.getObject(Init.java:28)
    at net.mindview.util.A.<init>(Init.java:8)
    at net.mindview.util.B.<init>(Init.java:21)
    at net.mindview.util.Init.main(Init.java:34)
  • What is leading you to think **object** is null? Is a **NullPointerException** thrown? – SamTebbs33 Jun 16 '15 at 22:22
  • I would suggest doing a stack trace and using break points to pinpoint the exact location of your error. What error are you getting? Where are you getting it? It's hard for us to know this without seeing the message you are getting. – Evan Bechtol Jun 16 '15 at 22:22
  • @EvanBechtol the output has been added, the problem exactly in the object object in class B .. which it says it has not been initialized yet. – Waseem Swaileh Jun 16 '15 at 22:25
  • This is one of the classic blunders. Trying to use an object that has not been properly constructed. Never call a non final public method in a constructor or initialisation block. – BevynQ Jun 16 '15 at 22:27
  • @EvanBechtol Maybe it has something to do with, class B will never be initialized before class A which is the base class has fully initialized? but when then the object will be initialized in class B? – Waseem Swaileh Jun 16 '15 at 22:28

6 Answers6

4

According to this answer:

The correct order of initialisation is:

  1. Static variable initialisers and static initialisation blocks, in textual order, if the class hasn't been previously initialised.
  2. The super() call in the constructor, whether explicit or implicit.
  3. Instance variable initialisers and instance initialisation blocks, in textual order.
  4. Remaining body of constructor after super().

See sections §2.17.5-6 of the Java Virtual Machine Specification.

So basically, object in class B is not initialized yet during constructor of class A is being executed (point 2: implicit super() call).

Community
  • 1
  • 1
mostruash
  • 4,169
  • 1
  • 23
  • 40
  • Yes .. That was the problem .. Thanks dear .. ! ... What is the best way to avoid such a bug in the future .. is there any convention to follow ? – Waseem Swaileh Jun 16 '15 at 22:38
  • 1
    Yes there is. Don't call overridable methods from constructors: http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors – mostruash Jun 16 '15 at 22:40
3

Within B constructor you call A construct which is using B's getObject() which is using not initialized object from B. Use debugger step by step and you will see the flow.

Alex
  • 4,457
  • 2
  • 20
  • 59
2

The NPE is coming from the class itself, not object. While the constructor is working, this is null.

B extends A, so there's an implicit super constructor call inserted. That prints your "A Class" line, but then the method call is equivalent to this.getObject();, and this is null.

MattPutnam
  • 2,927
  • 2
  • 17
  • 23
1

I think the key point of this problem is that you should know that the constructor of super class (A in case) will be called first. let's assume antoher condition that A also extends C , in case, constructor of c will be called first.

so the order of call should be : 1 construtor of C, 2 constructor A and then constructor of B at the last.

For your case, because Constructor A was called first , at this point object is not initialized yet which cause the null pointer excetion

Jegg
  • 549
  • 3
  • 11
  • I think you are right here .. and the question become .. the B class will never initialized any of its values even the constructor before Class A which is the base class finish it's business, and in class of overridden method , the child method will be called instead of the base class ? – Waseem Swaileh Jun 16 '15 at 22:35
1

Execution orders are:

class A {

    Object object = new Object(); // --------------- 2

    public A() {
        System.out.println("A Class"); // ---------- 3
        getObject(); // ---------------------------- 4 (calls B.getObject())
    }

    public void getObject() {
        System.out.println("Class A Version");
        System.out.println(object.toString());
    }
}

class B extends A {

    Object object = new Object(); // --------------- 7 (not executed)

    public B() {
        System.out.println("B Class"); // ---------- 8 (not executed)
    }

    @Override
    public void getObject() {
        System.out.println("Class B Version"); // -- 5
        System.out.println(object.toString()); // -- 6 (exception!)
    }
}

public class Init {
    public static void main(String[] args) {
        new B();  // ------------------------------- 1
    }
}
1

You should never call overridable method in constructors as it introduces ambiguity in terms of which method to call. In you case your super class A calls B's getObject(). At this Point B is yet not instantiated so the call fails and gives you NPE.

juggernaut
  • 126
  • 18