简体   繁体   中英

Why does the program print the height value 0 instead of the one I set?

I am confused about how are the methods and constructors called at runtime, since the derived constructor is printed 3 times and the height is printed 0

I have tried printing some messages inside methods and constructors as to know what exactly is happening

public class Derived extends Base{
    public static void main(String args[]){
        System.out.println("Hello World");
        Derived d = new Derived();
    }

    protected Derived(){
        System.out.println("Inside Derived Const");
        showAll();
    }

    protected void showAll(){
        System.out.println("Inside Derived showAll");
        System.out.println(getClass().getName()+" : "+height);
    }

    double height = 106.0;
}

class Base{

    protected Base(){
        System.out.println("Inside Base Const");
        showAll();
    }

    protected void showAll(){
        System.out.println("Inside Base showAll");
        System.out.println(getClass().getName()+" : "+height);
    }

    double height = 196.0;
}

I expected the output to be

Hello world
Derived : 106
Base : 196

instead I am getting

Hello World
Inside Base Const
Inside Derived showAll
Derived : 0.0
Inside Derived Const
Inside Derived showAll
Derived : 106.0

It's because you derived the Derived class from Base class and shadowing the variable and also overriding the methods.

You're calling the constructor of the Base class whenever you're instantiating the Derived class with:

Derived d = new Derived();

Here what happens when you're calling the above code:

  • Constructor of Base class Base() is called,
  • then "Inside Base Const" is printed,
  • method showAll() is not called because it's being override. Method showAll() inside the Derived class is called instead,
  • "Inside Base showAll" is printed,
  • "Derived : 106.0" is printed because double height = 196.0; inside Base class is being shadowed by double height = 106.0; inside the Derived class.

An important point to note is, when subclass object is created, a separate object of super class object will not be created.

Only a subclass object is created that has super class variables.

so we unable to blindly say that whenever a class constructor is executed, object of that class is created or not. Please refer to below changes and see.

public class Derived extends Base {
    public static void main(String args[]) {
        System.out.println("Hello World");
        Derived d = new Derived();
        d.getClass();
    }

    protected Derived() {
        System.out.println("Inside Derived Const");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(this.getClass().getName());
        showAll();
    }

    protected void showAll() {
        System.out.println("Inside Derived showAll");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(getClass().getName() + " : " + height);
    }

    double height = 106.0;
}

class Base {

    protected Base() {
        System.out.println("Inside Base Const");
        System.out.println("Super class object hashcode :" + this.hashCode());
        System.out.println(this.getClass().getName());
        showAll();
    }

    protected void showAll() {
        System.out.println("Inside Base showAll");
        System.out.println("Sub class object hashcode :" + this.hashCode());
        System.out.println(getClass().getName() + " : " + height);
    }

    double height = 196.0;
}

Output

Hello World
Inside Base Const
Super class object hashcode :1917513796
Derived
Inside Derived showAll
Sub class object hashcode :1917513796
Derived : 0.0
Inside Derived Const
Sub class object hashcode :1917513796
Derived
Inside Derived showAll
Sub class object hashcode :1917513796
Derived : 106.0
  • As we can observe that both super class(Base) object hashcode and subclass(Derived) object hashcode are same, so only one object is created.

  • This object is of class Derived as when we try to print name of class which object is created, it is printing "Derived" which is subclass.

  • When you have called showAll() in super class for first time it doesn't have a value for height variable because of the method showAll has overridden.But the value has not assigned at that line it calls.

  • When the method showAll() has called inside the subclass it has the value assigned which is 196.0. This is due to variable hiding*.

( Variable hiding: When the child and parent classes both have a variable with the same name, the child class' variable hides the parent class' variable.)

You have stumbled upon a major deficiency in the workings of java (and other object-oriented languages.) This deficiency is allowed by the compiler, but any decent IDE will detect it and show you a warning, so the fact that you are posting this question tells me that you are compiling without some very important warnings enabled. Go enable as many warnings as you can on your IDE, and your IDE will point the problem out to you. But I will now explain it anyway.

In the constructor of your base class, you are invoking showAll() . This is a non-final method, so any derived class may override it.

It is a grave mistake to invoke an overridable method from within a constructor .

You see, at the moment that the base class constructor is being invoked, the derived class constructor has not been invoked yet, and the object has not been fully initialized. So, what is simply happening is that at the moment that your base class constructor is running, your statement double height = 106.0; of your derived class has not been executed yet. That's why the height member of your derived class appears to contain zero. Zero is simply the default, and 106.0 has not been stored in it yet.

If you enable the right warnings in your IDE, then your IDE will warn you about any invocations of non-final methods from within a constructor. (In my opinion, this should not be a warning, it should be an error.)

So, let me briefly address each of your expectations vs. results:

You expected the following:

Hello world
Derived : 106
Base : 196

That's wrong. If you had no other mistakes, you should have expected the following:

Hello world
Base : 196
Derived : 106

That's because your Derived constructor starts with an implicit (hidden) call to the Base constructor, so the base constructor will always be invoked first. This is evident by your System.out.println("Inside X Const") statements.

But instead you got the following:

Hello World
Derived : 0.0
Derived : 106.0

Both lines appear to come from the 'Derived' class, because getClass() will return the class of the current object, and you have only created one object, which is an instance of Derived . So, getClass() will return Derived when invoked from within the Derived class, and it will also return Derived when invoked from within the Base class.

And then the 0.0 as I have already explained comes from the uninitialized member variable of the Derived instance, since you are invoking the showAll() overridable from within the constructor of the base class, so the derived class has not had a chance to initialize itself at the moment that the method is invoked.

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