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