Superclass method being called even though object is of subclass

Prasad Kharkar :

I was playing around with simple overloading overriding rules and found something interesting. Here is my code.

package com.demo;

public class Animal {

    private void eat() {
        System.out.println("animal eating");
    }

    public static void main(String args[]) {

        Animal a = new Horse();
        a.eat();
    }
}

class Horse extends Animal {
    public void eat() {
        System.out.println("Horse eating");
    }
}

This program outputs the below.

animal eating

Here is what I know:

  • As we have private void eat() method, it is not definitely going to be accessed in a subclass, so the question of method overriding does not arise here as JLS defines it clearly.
  • Now that this is not method overriding, it is definitely not going to call public void eat() method from the Horse class
  • Now our declaration Animal a = new Horse(); is valid because of polymorphism.

Why is a.eat() invoking a method from the Animal class? We are creating a Horse object, so why does the Animal class' method get called?

Adrian Shum :

I am not sure if I understand your confusion. Based on what you know:

You are right, Horse.eat() is not overriding Animal.eat() (as it is private). In another word, when you call anAnimal.eat(), no late-binding happens and hence, you are simply calling Animal.eat(), which is what you see.


From your other comment, seems that your confusion is how the compiler is deciding what to call. Here is a very high-level explanation:

When compiler sees Animal a =...; a.eat();, it will try to resolve what to call.

For example, if it sees eat() is a static method, given a is a reference to Animal, compiler will translate it to call Animal.eat().

If it is an instance method, and it encounters a method that may have been overridden by a child class, what the compiler does is, it will not generate instructions to call a specific method. Instead, it will generate instructions to do some kind of lookup from a vtable. Conceptually, each object will have a little table, which the key is the method signature, and the value is the reference to the actual method to call. For example, if in your case, Animal.eat() is not private, what Horse's vtable will contain is something like ["eat()" -> "Horse.eat()"]. So at runtime, given an Animal reference and eat() is called, what happen is actually: lookup from the vtable of the referred object with eat(), and call the method associated. (If the ref is pointing at a Horse, the method associated will be Horse.eat() ). This is how the magic of late binding is done in most cases.

With an instance method that is not possible to be overridden, compilers do similar things as static methods and generate instructions to call that method directly.

(The above is not technically accurate, just a conceptual illustration for you to understand what happened)

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=421247&siteId=1
Recommended