0

In the below code , I have three questions. I know that having same function in both Parent and Child class does not make any sense and not at all a good design. But , since Java is allowing me to do this , it was possible to write the below code. Trying to understand what actually happens under the hood.

1.When I call f() from the constructor of class A I found that it is calling the child class f(). This is an expected behaviour. But , when the parent constructor calls the overloaded f() before initialising the child class members ,why “B” is getting printed.

2.Why I have two values for a final variable X (x=null , x=B)?.

class A{
    A(){
        System.out.println("A's Constructor");
        f();
    }
    void f() {System.out.println("A");}
}

class B extends A{
    B(){
        System.out.println("B's Constructor");
        f();
    }
    final String x = "B";
    void f() {System.out.println(x);}
}

public class JavaPOCSamples {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //System.out.println("Java POC");
        new B();
    }

}

Output as below when “B”.trim() is used in the above code:

A's Constructor
null // Note that a final variable X is null
B's Constructor
B // Note that a final variable X is changed to "B"
user3742125
  • 617
  • 2
  • 9
  • 31
user3656231
  • 431
  • 2
  • 7
  • 17
  • 2
    why would that be weird? It's the process of the constructor that initializes your values, your first print is before your construction is finished. So far, it is only constructing your A class, which doesn't contain (so, doesn't set) the x value. – Stultuske Dec 06 '19 at 08:10
  • You overloaded method `f`, so when object `B` is initialized, B's method will be called. In this scenario, A's method `f` is never called. – mrhd Dec 06 '19 at 08:13
  • may be duplicate of https://stackoverflow.com/questions/3330390/state-of-derived-class-object-when-base-class-constructor-calls-overridden-metho – Jonathan Niu Dec 06 '19 at 08:32
  • @Stultuske. But , if I change the statement in my code from final String x = “B”.trim() to final String x = “B” then it prints “B”. So if parent class constructor calls f() before the child class construction then why “B” is getting printed. It means that B is set to variable x right?? – user3742125 Dec 06 '19 at 09:10
  • @Stultuske: Doesn't `A`'s function print "A"? I pointed out that that function is not called. – mrhd Dec 06 '19 at 09:28
  • @user727089 I misread, I thought you meant to say that A's f is called when A's constructor executes. – Stultuske Dec 06 '19 at 09:51
  • @Stultuske : any inputs on my comments - “ if I change the statement in my code from final String x = “B”.trim() to final String x = “B” then it prints “B”. So if parent class constructor calls f() before the child class construction then why “B” is getting printed. It means that B is set to variable x right??” – user3742125 Dec 06 '19 at 10:40

2 Answers2

3

It is exactly the expected behaviour and is exactly why you should never call overridable methods from a constructor.

The constructor of B first calls the constructor of A, that calls f(), (from class B because it's overridden), that prints x, which is still null. Then B sets it's initialized member variables (so x is no longer null), prints something and calls f() again...

Nicktar
  • 5,548
  • 1
  • 28
  • 43
  • But , if I change the statement from final String x = “B”.trim() to final String x = “B” then it’s print “B”. So if parent constructor call overloaded f() before initialising the child class members then why “B” is getting printed. – user3742125 Dec 06 '19 at 09:02
2

That's is because of the Java Language Specification of Inheritance. Here is a quote from Oracle Java docs.

With super(), the superclass no-argument constructor is called. With super(parameter list), the superclass constructor with a matching parameter list is called.

Note: If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.

Small & Simple Explanation:

super() means the constructor (equivalent) of immediate parent class.

class A{
    A(){
        System.out.println("A's Constructor");
        f();
    }
     // overloaded constructor 
     // calling super(int a) in child class will call this 
    A(int a){
        System.out.println("A's Constructor " + a);
        f();
    }
    void f() {System.out.println("A");}
}

Specs means, in an inheritance, when an object of the Child Class is created/instantiated, the Object of the Parent Class must instantiate first. So by default super() is invoked always even if you don't invoke it explicitly (any of the overloaded super(arg...) method) in your code.

If you call an overloaded super(args...) of your parent class from your child class, then the default super() is not called.

That means, in your code, Java Compiler puts the default line of super() at very first line in the child constructor, when you don't invoke any of super constructors.

Practical Proof ?? (in your code..??)

    class A{
        A(){
            System.out.println("A's Constructor");
            f();
        }
         // overloaded constructor 
         // calling super(int a) in child class will call this 
        A(int a){
            System.out.println("A's Constructor " + a);
            f();
        }
        void f() {System.out.println("A");}
    }

    class B extends A{
        B(){
            // super(); java adds this line when you don't put any super(args...) call
            System.out.println("B's Constructor");
            f();
        }

        B(int a){
            super(a);
            System.out.println("B's Constructor "+ a);
            f();
        }
        final String x = "B".trim();
        void f() {System.out.println(x);}
    }

    public class Main {

        public static void main(String[] args) {
            // TODO Auto-generated method stub
            //System.out.println("Java POC");
            new B(5);
        }

    }

Output: (Read comments for some hints..)

A's Constructor 5
null
B's Constructor 5
B

try to play with super() calls.. and get more questions to learn Java deeper. :)

Cheers!!


Recommended reads...

https://stackoverflow.com/a/3767389/6446770

https://stackoverflow.com/a/3767391/6446770

https://stackoverflow.com/a/3767421/6446770

Community
  • 1
  • 1
miiiii
  • 1,580
  • 1
  • 16
  • 29