Below is the java class having 3 overloaded constructors :
public class Test {
public Test(Object i){
System.out.println("Object invoked");
}
public Test(String i){
System.out.println("String invoked");
}
public Test(int k){
System.out.println("Integer invoked");
}
public static void main(String[] args) throws Exception {
Test t = new Test(null);
}
}
If null value is passed while creating the new instance of class, which constructor will be invoked ? What is the reason ?
Java always chooses the most specific method (or constructor) that would be applicable for the argument you pass. In this case, that's the
String
constructor --String
is a subclass ofObject
.Think about what would happen if you had
Both the
Object
andString
constructors would be applicable here. After all, the argument is both anObject
and aString
. However, it is clear that theString
constructor will be invoked because it is more specific than theObject
constructor and still is applicable given the argument.null
is no different; these two constructors are still applicable, and theString
constructor is still chosen over theObject
one for the same reason.Now, if there were two equally "specific" constructors present (e.g. if you had an
Integer
constructor) there would be a compilation error when you callTest(null)
.This is outlined in more detail in JLS §15.12.2:
The explicit process of determining which method is the most specific is outlined in JLS §15.12.2.5.
The answer is:
Test(String)
is invoked.Why?
When determining which of a set of overloaded methods will be invoked, the Java compiler will attempt to match the most concrete type. And it will first attempt to match a signature before employing autoboxing. (@arshajii provided a perfect reference into the Java Language Spec on this)
Here,
Object
is the most abstract class in the type system.String
subclasses fromObject
and is therefore more specific/concrete.The logic behind this is that if you are overloading a method with a more specific-typed parameter, you're likely wanting to do more with that object (when you subclass, you typically add methods). If method signature determination worked the other way (i.e. the more abstractly-typed signature winning; here,
Test(Object)
), then none of the more concrete signatures would ever get called.