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.