javaconstructoroverridingjava-11

Understanding method overriding and constructor behavior in Java inheritance


I'm trying to understand the behavior of method overriding, constructor calls, and variable shadowing in Java inheritance. I have the following code

class Base {
    int id = 1000; //Line n1

    Base() {
        Base(); //Line n2
    }

    void Base() { //Line n3
        System.out.println(++id); //Line n4
    }
}

class Derived extends Base {
    int id = 2000; //Line n5

    Derived() {} //Line n6

    void Base() { //Line n7
        System.out.println(--id); //Line n8
    }
}

public class Test {
    public static void main(String[] args) {
        Base base = new Derived(); //Line n9
    }
}

When I run this code, it outputs -1.

I understand that Derived extends Base, and both classes have an id variable and a Base() method. The order is as follow

  1. call constructor of Derived
  2. call constructor of Base
  3. call Base() method, due to method overriding, the method in the child class is executed.

Therefor, in my opinion, the result will be 1001.


Solution

  • This is because of the way java constructors are working.

    The first instruction of a constructor will always be this.super(), event if not written in your code.

    While this.super() is called, variables aren't affected and have their default value (which is 0 for ints).

    So, you are removing 1 to id (that equals 0).

    You can test with this code:

    class Base {
        int id = 1000;
    
        Base() {
            System.out.println("Base constructor called");
            Base();
        }
    
        void Base() {
            System.out.println("Base called");
            System.out.println(++this.id);
        }
    }
    
    class Derived extends Base {
        int id = 2000;
    
        Derived() {
            System.out.println("==Super finished==");
            Base();
        }
    
        void Base() {
            System.out.println("Derived base called");
            System.out.println(--this.id);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            new Derived();
        }
    }
    

    The output will be :

    Base constructor called
    Derived base called
    -1
    ==Super finished==
    Derived base called
    1999
    

    However, if your main was :

    public class test {
        public static void main(String[] args) {
            new Base();
        }
    }
    

    then, your output would be the following :

    Base constructor called
    Base called
    1001
    

    This is because, in that case:


    The behavior described here may change in future versions of Java, beyond Java 23. Work is underway to make constructors more flexible. See JEP 482: Flexible Constructor Bodies (Second Preview).