Search code examples
javaooppolymorphismdispatch

Confusing method bindings


The output of this simple program is This is base.

public class mainApp{
    private void func(){
      System.out.println("This is base"); 
    }

    public static void main(String[] args){
        mainApp newObj = new derived();
        newObj.func();
    }
}

class derived extends mainApp{
    public void func(){ 
      System.out.println("This is derived"); 
    }
}
  • My question is when we are using this line mainApp newObj = new derived(); are we not actually creating an object of derived class using a reference of base class mainApp. So, when I am using the object to call it's method why don't I get the method from the derived class? Why I get the method from the base class.

  • using this line, mainApp newObj = new derived();, are we working with a reference of mainApp OR we are working with an object of derived class. Which one is correct?


Solution

  • The reason that you're getting the base class method is that the base class version of func is declared private, and Java does not allow private methods to be overridden by subclasses. This means that if you extend a base class and by pure coincidence decide to name a private member function the same name as a private member function in the base class, you don't accidentally change the behavior of the base class's member functions. You are indeed working with an object of type derived, but because the reference is statically typed as a mainApp, calling func is interpreted as calling the private method func in mainApp rather than the public method func in derived. Changing the code to read

    derived d = new derived();
    d.func();
    

    fixes this, because the static type of d is now derived and the call to func has a different meaning.

    At the JVM bytecode level, the instruction used to call private member functions is invokespecial whereas the instruction used to call normal, override-able member functions is invokevirtual. The two have totally different semantics; invokespecial begins looking in the current class (or some base class for things like constructors), whereas invokevirtual looks in the class corresponding to the object's type at runtime.