According to my understanding:
Private, final and static methods of a class follow compile time binding i.e. 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)
.
See more on this question at Stackoverflow