Why following program every time prints I'm string
and not I'm object.
or I'm int.
?
public class Demo {
public Demo(String s){
System.out.println("I'm string");
}
public Demo(int i){
System.out.println("I'm int.");
}
public Demo(Object o){
System.out.println("I'm object.");
}
public static void main(String[] args) {
new Demo(n开发者_运维知识库ull);
}
}
Also if I replace int
with Integer
. It gives error as The constructor Demo(String) is ambiguous.
Why?
null
can be converted to Object
or String
, but not int
. Therefore the second constructor is out.
Between the conversion to Object
or the conversion to String
, the conversion to String
is more specific, so that's what's picked.
The JLS section 15.12.2 describes method overload resolution, and I believe the same approach is used for constructor resolution. Section 15.12.2.5 describes choosing the most specific method (constructor in this case):
The informal intuition is that one method 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.
This about the constructor invocation with Object or String arguments - any invocation handled by new Demo(String)
could also be passed on to new Demo(Object)
without a compile-time type error, but the reverse is not true, therefore the new Demo(String)
one is more specific... and thus chosen by the overload resolution rules.
To answer your second question (since Jon Skeet has already covered the first), when you have both a String
constructor and an Integer
constructor the compiler doesn't know what you mean by null
in new Demo(null)
: it could be either a String
or an Integer
.
Because String
can't be cast to Integer
(and vice versa) the compiler gives up and reports the ambiguous error. This is in contrast to the String
vs Object
choice when you don't have the Integer
constructor.
When you have constructors or methods like the above, the compiler generally tries to find the closest match possible and uses that.
The way to think of null
in these circumstances is it acts as a subtype of all types (yes, it's not strictly speaking true but it provides a good platform for thinking about what happens). So using this rule it fits string more closely than object, hence this is the constructor that is executed.
The fact the String constructor is mentioned in by the compiler in your second error:
The constructor Demo(String) is ambiguous.
is not significant. This is because the Constructor which takes a String is the first declared constructor, so the compiler uses it in its error message. Change to have the Object constructor first and you get:
The constructor Demo(Object) is ambiguous.
What it's trying to say is there's ambiguity between the constructor which takes the Integer and the Object, so you have to be more specific, as null can be applied to each. Integer IS-NOT-A String, so the two types are not compatible. You need to be more specific so the compiler can bind the constructor call.
See @Jon Skeet answer for why the compiler raises an error in some instances and not in others.
精彩评论