2

**Java code-MySuper class is the parent class and is extended by MySub class.I am creating the object MySub mySub = new MySub().I thought the output would be "y" but when I tried to run the code it was showing null as an output **

class MySuper {
    String strl = "x";

    public MySuper() {
        myMethod();
    }

    void myMethod() {
        System.out.print(strl);
    }
}

class MySub extends MySuper {
    String str2 = "y";

    void myMethod() {
        System.out.print(str2);
    }

    public static void main(String[] args) {

        MySub mySub = new MySub();
    }
}   
azro
  • 53,056
  • 7
  • 34
  • 70
  • maybe you should define if the Strings are public or private. you should also give MySub an constructor and inside of the constructor call the super method – Anton May 21 '22 at 07:47
  • Does this answer your question? [Java Constructor and Field Initialization Order](https://stackoverflow.com/questions/10589828/java-constructor-and-field-initialization-order) – Ole V.V. May 21 '22 at 07:48

3 Answers3

2

The implicit constructor used by MySub looks like this:

class MySub extends MySuper {

  String str2;

  MySub() {
    super();
    str2 = "y";
  }

  // rest omitted for brevity
}

While inline field initialization is technically moved into the constructor, that's not necessarily important to know in and of itself. The important part is that the super constructor is invoked before the subclass's fields are initialized. So, when the super constructor invokes the myMethod() method, which is overridden by the subclass, the str2 field has not yet been assigned a non-default value. This results in your code printing out null.

And this is why you should avoid invoking overridable methods in a constructor.

Slaw
  • 37,820
  • 8
  • 53
  • 80
1

This is due to Java dynamic method dispatch.

In your example. when you're instancing with the default constructor a MySub instance, this implicitly performs a call to the superclass' constructor. Within the superclass' constructor there is a call to myMethod() which is declared in MySuper and overridden in MySub.

Now, even if myMethod is being called from the superclass' constructor, which could fool us into thinking that the superclass' version of myMethod is being called, this is not what is actually happening.

The instance that is performing all these calls is still a MySub instance; therefore the myMethod implementation that is being invoked by Java is the closest implementation to MySub, i.e. the myMethod overridden by MySub.

So, if in this case the myMethod version that is being invoked in the superclass' constructor is the one overridden by MySub, why it's not printing str2 value? This is because, although method calls are dynamically dispatched, fields are statically dispatched. In Java, only methods can override their base class' methods. Child class' fields can only shadow base class' fields (with the same name). So Java already knows at compile time which fields are being used and only at run time which method implementations are being invoked. This means that when you're using a field in a child class, you can be sure that the one you're using is always the one you're referring to.

Getting back to your example, since myMethod is being invoked from the superclass' constructor, at this point we're still initializing the parent object, the child class' fields have not been initialized yet, they still contain their default values (the default value for references is null). So, in your dynamically dispatched myMethod we are printing the value of the statically dispatched str2 which is still at null because the child class initialization has not happened yet.

Dan
  • 3,647
  • 5
  • 20
  • 26
-1

Minor Mistakes:

  1. null output is coming because of extending the MySuper class and extending MySuper class is not required because the default class object can be created anywhere in a package without extending that.
  2. You have not called the method myMethod() after creating the object mySub.That's why it is not printing the output as y.

Solution: Try the code below, it is working smoothly.

 class MySuper {
        String strl = "x";
        public MySuper() {
            myMethod();
        }
        void myMethod() {
            System.out.print(strl);
        }
    }
    // class MySub extends MySuper {
        class MySub {
        String str2 = "y";
        void myMethod() {
            System.out.print(str2);
        }
        public static void main(String[] args) {
            MySub mySub = new MySub();
           // extra line added
            mySub.myMethod();
            MySuper ms=new MySuper();
        }
    }