Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if you call an overridden method using super in a constructor

There is two classes Super1 and Sub1

Super1.class

public class Super1 {
    Super1 (){
        this.printThree();
    }

    public void printThree(){
        System.out.println("Print Three");
    }    
}

Sub1.class

public class Sub1 extends Super1 {
    Sub1 (){
        super.printThree();
    }

    int three=(int) Math.PI;

    public void printThree(){
        System.out.println(three);
    }

    public static void main(String ...a){
         new Sub1().printThree();
    }
}

When I invoke the method printThree of class Sub1 I expected the output to be:

Print Three
3

Because Sub1 constructor calling the super.printThree();.

But I actually get

0
Print Three
3

I know 0 is default value of int but how it is happening ?

like image 298
Roushan Avatar asked Oct 28 '15 17:10

Roushan


People also ask

Can you use super in a constructor?

In the constructor body of a derived class (with extends ), the super keyword may appear as a "function call" ( super(... args) ), which must be called before the this keyword is used, and before the constructor returns.

Can Super method be overridden?

When a method in a subclass has the same name, same parameters or signature, and same return type(or sub-type) as a method in its super-class, then the method in the subclass is said to override the method in the super-class. Method overriding is one of the way by which java achieve Run Time Polymorphism.

Can you use this () and super () both in a constructor?

“this()” and “super()” cannot be used inside the same constructor, as both cannot be executed at once (both cannot be the first statement). “this” can be passed as an argument in the method and constructor calls.

Can you invoke an overridden superclass method from a subclass?

The overridden method shall not be accessible from outside of the classes at all. But you can call it within the child class itself. to call a super class method from within a sub class you can use the super keyword.


2 Answers

You're seeing the effects of three things:

  1. Default super-constructor calls, and

  2. Instance initializers relative to super calls, and

  3. How overridden methods work

Your Sub1 constructor is really this:

Sub1(){
    super();               // <== Default super() call, inserted by the compiler
    three=(int) Math.PI;   // <== Instance initializers are really inserted
                           // into constructors by the compiler
    super.printThree();
}

(Surprising, I know, but it's true. Use javap -c YourClass to look. :-) )

The reason it looks like that is that the superclass must have a chance to initialize its part of the object before the subclass can initialize its part of the object. So you get this kind of interwoven effect.

And given that that's what Sub1 really looks like, let's walk through it:

  1. The JVM creates the instance and sets all instance fields to their defaults (all bits off). So at this point, the three field exists, and has the value 0.

  2. The JVM calls Sub1.

  3. Sub1 immediately calls super() (Super1), which...

    1. ...calls printThree. Since printThree is overridden, even though the call to it is in the code for Super1, it's the overridden method (the one in Sub1) that gets called. This is part of how Java implements polymorphism. Since three's instance initializer hasn't been run yet, three contains 0, and that's what gets output.

    2. Super1 returns.

  4. Back in Sub1, the instance initializer code for three that the compiler inserted (relocated, really) runs and gives three a new value.

  5. Sub1 calls printThree. Since three's instance initializer code has now run, printThree prints 3.

With regard to this instance initializer code getting moved into the constructor, you might be wondering: What if I have more than one constructor? Which one does the code get moved into? The answer is that the compiler duplicates the code into each constructor. (You can see that in javap -c, too.) (If you have a really complicated instance initializer, I wouldn't be surprised if the compiler effectively turned it into a method, but I haven't looked.)

It's a bit clearer if you do something really naughty and call a method during your instance init: (live copy)

class Super
{
    public static void main (String[] args) {
        new Sub();
    }

    Super() {
        System.out.println("Super constructor");
        this.printThree();
    }

    protected void printThree() {
        System.out.println("Super's printThree");
    }
}
class Sub extends Super
{
    int three = this.initThree();

    Sub() {
        this.printThree();
    }

    private int initThree() {
        System.out.println("Sub's initThree");
        return 3;
    }

    protected void printThree() {
        System.out.println("Sub's printThree: " + this.three);
    }
}

Output:

Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3

Note where "Sub's initThree" came in that sequence.

like image 123
T.J. Crowder Avatar answered Oct 08 '22 04:10

T.J. Crowder


When the instance is created, the Sub1 constructor is called.

The first instruction in any constructor is a call to the superclass constructor. If you don't have an explicit call, there will be an implicit call to the no-args constructor of Super1.

The no-args constructor is calling this.printThree(). This method is overridden in Sub1. Now, this part may be confusing, but even if the code is in the superclass, this.method() still refers to the overriding method.

So it's calling the printThree() in Sub1, which prints the uninitialized value of the variable three - 0.

Now that the superclass's constructor is done, it completes Sub1 constructor, which uses super.printThree(). Since it specifically says super, the method from Super1 is used rather than the overriding one. This prints the Print Three.

Now the Sub1 constructor is also done, and main calls the new instance's printThree(). Now three is already initialized, so you get the output 3.

like image 26
RealSkeptic Avatar answered Oct 08 '22 06:10

RealSkeptic