Neetagupta is correct that the method profiles are different, and therefore overriding and polymorphism are irrelevant to this problem. It's about over
loading - the compiler needs to be able to choose which of the overloaded method signatures is more appropriate to use. This is covered in detail in the
Java Language Specification
here. Basically the compiler tries to determine if one method profile is more
specific than the others, and if so, that's the one to use. One method declaration is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error. In this case:
(assume a and b are instances of classes A and B respectively.)
"a.test(b)" could be handled by A.test(B) but not by B.test(A), so A.test(B) is not more specific than B.test(A).
"b.test(a)" could not be handled by A.test(B), but it could be B.test(A), so B.test(A) is not more specific than A.test(B).
Since neither method is more specific than the other, any invocation that could apply to both (i.e. "b.test(b)") is ambiguous, and causes an error.
If you also supply a B.test(B), then this new profile is more specific than the others, and any invocation that applies to B.test(B) (as well as the others) will indeed call B.test(B) without ambiguity.