Ofek Ron Ofek Ron - 4 months ago 8
Java Question

Why overload with param of sub class type is not choosen over some parent class

public class Imp1 implements Inter1 {
private int num;

@Override
public void apply() {
num++;
}

public void doubler() {
num = num * 2;
}

public boolean equals(Imp1 o) {
if (!(o instanceof Imp1))
return false;
return o.num == num;
}

public int getNum() {
return num;
}

public static void main(String[] args) {
final Inter1 a = new Imp1();
final Imp1 b = new Imp1();
a.apply();
b.apply();
System.out.println("a equals b " + a.equals(b));
System.out.println("b equals a " + b.equals(a));
}

}


I would expect
equals(Imp1 o)
to be choosen as the best candidate for
a.equals(b)
and
b.equals(a)
why is it not the case here?

In more details - this codes outputs twice false and i am wondering why?
a and b holds Imp1 object, hence calling equals with Imp1 instance as param should invoke
equals(Imp1 o)
which fits better than
equals(Object o)
, yet i see that
equals(Object o)
is being invoked, and finally the code prints false twice instead of twice true.

Answer

Method overloading resolution is determined by the compile time type of the arguments, since the compiler chooses the best matching method signature at compile time.

equals(Imp1 o) can only be chosen if the compile-time type of the argument passed to the method is Imp1 or a sub-class of Imp1.

a does not meet this criteria, so b.equals(a) calls Object's equals.

As for a.equals(b), since the compile time type of a is not Imp1, it can't invoke the equals(Imp1 o) method (unless you cast it to Impl1), so it can only choose Object's equals.

System.out.println("a equals b " + ((Imp1)a).equals(b));

will call equals(Imp1 o).