Please consider the following code (Its quite simple)
public class Main {
public static class A{
int id;
public A(final int id){
this.id = id;
}
@Override
public boolean equals(final Object obj) {
if(obj instanceof A){
final A a = (A) obj;
return id == a.id;
}
return false;
}
}
public static void main(final String[] args) {
final List<A> items = new ArrayList<A>();
items.add(new A(0));
items.add(new A(1));
final Object obj = new A(1);
System.out.println(items.indexOf(obj));
}
}
When I run this code, 1
will be logged in the console. In my opinion it shouldn't be 1
rather it should be -1
. I've looked into the indexOf
source code. Exactly copy/paste from there:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
As we know when my code wants to be run the else
segment of the above code starts to execute. And as you can see in there, statement o.equals(elementData[i])
will be executed. So far everything is okay and I have no problems
My Problem
Type of variable o
in the above method is Object
and when we call equals
method of it, In my opinion equals
method of a generic Object will be executed, In the other side I've look at equals
method of Object source code. I copy/paste it here:
public boolean equals(Object obj) {
return (this == obj);
}
Now, in the for-loop at indexOf
method, It shouldn't any item be matched with o
object because there is no item in the array which is equal to o
object, in ==
point of view
Now I wonder how is output of my code equals to 1
. Can any one please help me?
Thanks
You're confusing the compile-time type of a variable with the execution-time type of its value.
The A.equals
method will be called rather than Object.equals
because of overriding - the execution-time type is used to determine which override of a method is used. If this weren't the case, custom equality overrides could never be used by ArrayList.indexOf
. Don't forget that the declared type of obj
is entirely unknown to the ArrayList.indexOf
code. All it has is the value of the o
parameter - which is a reference to an instance of A
.
It's really important to differentiate between compile-time types (which are used for overloading, checking what members are available etc) and the values at execution-time (which are used for overriding, instanceof
etc).
See more on this question at Stackoverflow