This is exactly as specified in JLS:
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
A String
is-a Object
, but not all Object
is-a String
. Therefore, String
is more specific than Object
, hence why the String
overload is chosen in the above example.
It is worth noting that this exact question (in essence) appeared in the wonderful Java Puzzlers (highly recommended), specifically Puzzle 46: The Case of the Confusing Constructor
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other
The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation. They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
I will close with a quote from Effective Java 2nd Edition, Item 41: Use overloading judiciously:
The rules that determine which overloading is selected are extremely complex. They take up thirty-three pages in the language specification, and few programmers understand all of their subtleties.
Needless to say, this book is also highly recommended.
See also
On explicit casting
So how can I invoke the Object
overload with null
argument?
Simple: cast the null
to type Object
. There are several scenarios where this is useful/necessary, and this is one of them.
What if I have an overload that takes, say, an Integer
?
Then the method invocation is ambiguous, and compile-time error occurs.
It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case [... with some exceptions] we say that the method invocation is ambiguous, and a compile-time error occurs.
To resolve the ambiguity, again you can cast the null
(or other expression) to the desired overload type.
See also