如下所示代码:

public class Example046 {

	private Example046(Object o) {
		System.out.println("Object");
	}

	private Example046(double[] dArray) {//2
		System.out.println("double array");
	}

	private Example046(String str) {//3
		System.out.println("string");
	}

	public static void main(String[] args) {
		new Example046(null);
	}
}


    输出说明:

    上述程序编译时会提示“The constructor Example046(Object) is ambiguous”错误,构造器是模糊不清的。如果去掉2或3构造函数中的一个,则能够正确执行。执行结果是2和3构造函数去掉后剩下的那个打印出来的。


    分析总结:

    要分析上述代码,需要先了解java重载的解析过程。Java 的重载解析过程是以两阶段运行的。 第一阶段选取所有可获得并且可应用的方法或构造器。第二阶段在第一阶段选取的方法或构造器中选取最精确的一个。如果一个方法或构造器可以接受传递给另一个方法或构造器的任何参数,那么我们就说第一个方法比第二个方法缺乏精确性。在上述代码中,第2个和第3个构造函数是精确的,第1个是不精确的,因为它可以接受2和3的任何参数。开始的程序中由于有两个精确的构造函数(2和3),编译器不知道选择哪一个,所以会提示错误。去掉其中的一个后,编译器可以确定精确的构造函数,所以会打印出来。

    要想用一个 null 参数来调用 (Object) 构造器,你需要这样写代码:new Example046((Object)null)。这可以确保只有 Example046(Object)是可应用的。更一般地讲,要想强制要求编译器选择一个精确的重载版本,需要将实际的参数转型为形式参数所声明的类型。

    在写代码时,上述重载构造函数是不推荐的。可以使用静态的构造函数和公用的工厂方法来替代重载。如果你确实进行了重载,那么请确保所有的重载所接受的参数类型都互不兼容,这样,任何两个重载都不会同时是可应用的。如果做不到这一点,那么就请确保所有可应用的重载都具有相同的行为

    总之, 重载版本的解析可能会产生混淆。应该尽可能地避免重载,如果你必须进行重载,那么你必须遵守上述方针,以最小化这种混淆。如果一个设计糟糕的API 强制你在不同的重载版本之间进行选择,那么请将实际的参数转型为你希望调用的重载版本的形式参数所具有的类型。



注:本【java解惑】系列均是博主阅读《java解惑》原书后将原书上的讲解和例子部分改编然后写成博文进行发布的。所有例子均亲自测试通过并共享在github上。通过这些例子激励自己惠及他人。同时本系列所有博文会同步发布在博主个人微信公众号搜索“爱题猿”或者“ape_it”方便大家阅读。如果文中有任何侵犯原作者权利的内容请及时告知博主以便及时删除如果读者对文中的内容有异议或者问题欢迎通过博客留言或者微信公众号留言等方式共同探讨。

源代码地址https://github.com/rocwinger/java-disabuse