为什么每次打印I'm string
而不是I'm object.
或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(null);
}
}
此外,如果我将int
替换为Integer
。它会给出错误The constructor Demo(String) is ambiguous.
为什么?
答案 0 :(得分:22)
null
可以转换为Object
或String
,但不能转换为int
。因此第二个构造函数已经出局。
在转换为Object
或转换为String
之间,转换为String
更加具体,因此这就是所选择的内容。
JLS section 15.12.2描述了方法重载解析,我相信相同的方法用于构造函数解析。 Section 15.12.2.5描述了选择最具体的方法(本例中为构造函数):
非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个没有编译时类型错误的调用,那么一个方法比另一个方法更具体。
这是关于使用Object或String参数的构造函数调用 - new Demo(String)
处理的任何调用也可以传递给new Demo(Object)
而没有编译时类型错误,但相反的是 not 是的,因此new Demo(String)
更具体......因此由重载决策规则选择。
答案 1 :(得分:3)
要回答你的第二个问题(因为Jon Skeet已经涵盖了第一个问题),当你同时拥有String
构造函数和Integer
构造函数时,编译器不知道你的意思{{ 1 {} null
:它可以是new Demo(null)
或String
。
由于Integer
无法转换为String
(反之亦然),编译器会放弃并报告模糊错误。当您没有Integer
构造函数时,这与String
vs Object
选项形成对比。
答案 2 :(得分:0)
当你有上述构造函数或方法时,编译器通常会尝试找到最接近的匹配并使用它。
在这些情况下考虑null
的方式是它作为所有类型的子类型(是的,它严格来说不是真的,但它提供了一个思考发生了什么的良好平台)。因此,使用此规则,它比对象更接近字符串,因此这是执行的构造函数。
答案 3 :(得分:0)
编译器在第二个错误中提到了String构造函数:
The constructor Demo(String) is ambiguous.
并不重要。这是因为采用String的构造函数是第一个声明的构造函数,因此编译器在其错误消息中使用它。更改为首先使用Object构造函数,然后得到:
The constructor Demo(Object) is ambiguous.
它试图说的是带有Integer和Object的构造函数之间存在歧义,所以你必须更具体,因为null可以应用于每个。整数IS-NOT-A字符串,因此这两种类型不兼容。您需要更具体,以便编译器可以绑定构造函数调用。
请参阅@Jon Skeet,了解编译器在某些情况下而不是在其他情况下引发错误的原因。