class Another {
public void method(Object o) {
System.out.println("This is in method which takes object");
}
public void method(String s) {
System.out.println("This is method which takes string");
}
}
public class NewClass {
public static void main(String args[]) {
Another an = new Another();
an.method(null);
}
}
When I try to execute this, I get
This is method which takes string
as the output. Why not "This is in method which takes object"? Object can also be null and string can also be null, why doesn't it invoke first method?
According to the Java Language Specification, in such cases of overloaded methods where both methods can handle the provided arguments, the method with more specific argument is chosen. Since String
is more specific than Object
(String
extends Object
), void method(String)
is chosen and called.
This is exactly as specified in JLS:
JLS 15.12.2.5 Choosing the Most Specific Method
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.
So how can I invoke the
Object
overload withnull
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.
JLS 15.12.2.5 Choosing the Most Specific Method
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.
The compiler will always find the narrowest match possible when resolving overloaded method calls.
Btw the Java convention is to use uppercase names for classes, i.e. Another
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With