Java flow-control

220 views Asked by At

Can anyone explain why this code is giving output as null? When I try to call new A() instead of new B(), it is printing the current date.

class A
{
    Date d = new Date();

    public A()
    {
        printDate();
    }

    void printDate() 
    {
        System.out.println("parent");
        System.out.println(d);
    }
}

class B extends A
{
    Date d = new Date();

    public B()
    {
        super();
    }

    @Override
    void printDate()
    {
        System.out.println("child");
        System.out.println(d);
    }
}

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

There are 5 answers

0
chiranjeevi On BEST ANSWER

After all inputs, I hope following answer satisfies,

As B also has field d, A.d is not inherited to B, where B has its own copy of d.

So when the control is in B.printDate(), it tries to look for A.d (because function is called from A).

this works fine if I remove following line from B

Date d = new Date();
6
Eran On

new B() invokes the constructor of B, which invokes the constructor of A. A's constructor calls printDate(), which, due to the overriding, executes B's printDate(), which prints the value of d variable of B. However, d variable of B is not initialized yet (it will only be initialized after the constructor of A is executed). Therefore it is still null (which is the default value for reference variables).

On the other hand, when you create an instance of A (new A()), printDate of A is called, and it prints the d variable of A, which was initialized prior to the constructor of A being executed.

In case it's not clear, B.d does not override A.d, it just hides it. Only methods can be overridden.

1
SonalPM On

Declare Date as Static

static Date d = new Date();
    public B(){
        super();
    }
    @Override
    void printDate(){
        System.out.println("child");
        System.out.println(d);
    }
0
Stephen C On

When you instantiate a B:

  1. the B constructor chains to the A constructor

  2. the A constructor calls printDate, but it is the B.printDate override that is called

  3. the B.printDate prints B.d.

  4. that gives null because the B.d field hasn't been initialized

  5. the printMethod returns, and the A constructor returns

  6. the fields of B are initialized, setting B.d to a non-null value. But its too late to affect the output.


Some lessons to learn from this:

  • It is a bad idea for a constructor to call an instance method on the object it is creating unless that instance method is either private or final. If you manage to call a method that has been overloaded by a subclass, then that method will see the instance variables of the subclass before they have been initialized ... and that's problematic.

  • It is a bad idea to use the same name for a (non-private) field in by a class and a subclass. Both fields will exist, and it can be difficult for someone reading the code to keep it right in their head.

  • Non-private instance fields are a bad idea. They are bad for encapsulation.

0
gashu On

This is because when you call super() then the Date variable d defined in class A gets initialized. Since in class B the variable d is an object variable, and it overwrites the variable d from parent class, and object variables are constructed only after the this pointer is constructed, you are getting null. If you want that to work as expected, make variable d in class B as static variable, which will then be initialized with class loading.