I came across this question in a quiz,
public class MoneyCalc {
public void method(Object o) {
System.out.println("Object Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
The output of this program is "String Version". But I was not able to understand why passing a null to an overloaded method chose the string version. Is null a String variable pointing to nothing ?
However when the code is changed to,
public class MoneyCalc {
public void method(StringBuffer sb) {
System.out.println("StringBuffer Verion");
}
public void method(String s) {
System.out.println("String Version");
}
public static void main(String args[]) {
MoneyCalc question = new MoneyCalc();
question.method(null);
}
}
it gives a compile error saying "The method method(StringBuffer) is ambiguous for the type MoneyCalc"
Additionally, the JLS 3.10.7 also declares that "null" is a literal value of the "null type". Therefore there exists a type called "null".
Later, the JLS 4.1 states that there exists a null type of which is impossible to declare variables, but you can use it through the null literal only. Later it says:
Why the compiler chooses to widen it to String might well be explained in Jon's answer.
As String type is more specific than Object type. Let's say you add one more method that takes an Integer type.
Then you will get a compiler error saying that the call is ambiguous. As now we two equally specific methods with same precedence.
I would say neither. NULL is a state not a value. Check out this link for more info on this (the article applies to SQL, but I think it helps with your question as well).
A null reference can be converted to an expression of any class type. So in the case of
String
, this is fine:The
String
overload here is chosen because the Java compiler picks the most specific overload, as per section 15.12.2.5 of the JLS. In particular:In your second case, both methods are still applicable, but neither
String
norStringBuffer
is more specific than the other, therefore neither method is more specific than the other, hence the compiler error.Java compiler gives most derived class type to assign null.
Here is the example to understand it :
output: B Class.
on the other hand:
Result : The method fun(C) is ambiguous for the type MyTest
Hope it will help to understand this case better.
To answer the question in the title:
null
is neither aString
nor anObject
, but a reference to either can be assigned tonull
.I'm actually surprised this code even compiles. I tried something similar previously and I got a compiler error saying that the call was ambiguous.
However, in this case, it seems like the compiler is choosing the method which is lowest on the food chain. It's assuming that you want the least generic version of the method in order to help you out.
I'll have to see if I can dig up the example where I got a compiler error in this (seemingly) exact same scenario, though...]
EDIT: I see. In the version I made, I had two overloaded methods accepting a
String
and anInteger
. In this scenario, there is no "most specific" parameter (as inObject
andString
), so it can't choose between them, unlike in your code.Very cool question!