简体   繁体   中英

compile-time and run-time binding in method overloading and overriding

According to my understanding:

Private, final and static methods of a class follow compile time binding ie which method will be called is decided at compile time.

But, call to non-private instance method is decided at run-time.

This used to solve all my problems till now. But, I stuck in some problem where the above statements are not deriving the correct output.

Here is the code:

class Item
{
    Integer size;
    Item(Integer size)
    {
      this.size=size;
    }
    public boolean equals(Item item2) //not overriding the method of Object class
    {
        if(this==item2)
        return true;
        return this.size.equals(item2.size);
     }

  }

public class Test 
{
    public static void main(String[] args)
     {
        Item itemA= new Item(10);
        Item itemB= new Item(10);
        Object itemC=itemA;
        System.out.println("|"+ itemA.equals(itemB) + "|" + itemC.equals(itemB)+ "|");
     }

}

Output it is giving: |true|false|

Output I expected: |true|true|

Here, the equals method of class Item is not overriding the equals method of Object but overloading is taking place because of different method signature of equals method.

Question: In the call itemC.equals(itemB) , why the equals method of Object class is getting called.

According to me: itemC is having object of class Item at run-time, therefore, equals of Item class should get called. At run-time there are two equals methods in Item class , one is its own and other one is inherited from Object class. So, equals(Item) should get called instead of equals(Object) because the call is for equals(Item) .

What exactly am I missing conceptually?

Question: In the call itemC.equals(itemB), why the equals method of Object class is getting called.

Because the compile-time type of itemC is Object .

Overriding is performed at execution time based on the actual type of the target object, but overloading is performed at compile time based on the compile-time type of the target expression.

If you use javap -c -v Test you'll see the two method calls involved:

Constant pool:

...
#6 = Methodref #2.#32    //  Item.equals:(LItem;)Z
#7 = Methodref #16.#33   //  java/lang/Object.equals:(Ljava/lang/Object;)Z
...

Then the main method:

33: invokevirtual #6  // Method Item.equals:(LItem;)Z
...
40: invokevirtual #7  // Method java/lang/Object.equals:(Ljava/lang/Object;)Z

So that shows the signatures for the methods that are being called. Which implementation of that signature is executed depends on the execution-time type. So if you override equals(Object) in Item , then that override will be called for itemC.equals(itemA) .

Overloading is determined at compile time, not runtime. Therefore, itemC.equals(itemB) calls equals method of Object , since the type of itemC variable is Object .

Snippet from jls reg overloading

When a method is invoked (§15.12), the number of actual arguments (and any explicit type
arguments) and the compile-time types of the arguments are used, at compile time, to determine the 
signature of the method that will be invoked (§15.12.2). If the method that is to be invoked is an 
instance method, the actual method to be invoked will be determined at run time, using dynamic method 
lookup (§15.12.4). 

based on the above statement, itemC.equals(itemB) invokes the equals method of Object class, since at compile type itemC is Object

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM