每this question,Java将选择"最具体的"尝试在不明确的重载构造函数之间进行选择时的选项。在这个例子中:
public class Test{
private Test(Map map){
System.out.println("Map");
}
private Test(Object o){
System.out.println("Object");
}
public static void main(String[] args){
new Test(null);
}
}
它会打印
"地图"
但是,我试图找出具体的"最具体的"手段。我认为这意味着"最不模糊的",因为"可能指的是尽可能少的类型。"在此上下文中,Object
可能是任何不是原语的内容,而Map
可能只是Map
或? extends Map
。基本上,我假设选择了接近继承树的叶子的类。当一个类是另一个类的子类时,这是有效的:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(B b){
System.out.println("B");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
" B"
然后我想出了这个:
public class Test{
private Test(A a){
System.out.println("A");
}
private Test(E e){
System.out.println("E");
}
public static void main(String[] args){
new Test(null);
}
}
class A{}
class B extends A{}
class C{}
class D extends C{}
class E extends D{}
我认为它应该打印E
,因为E
可能只引用一种已知类型,而A
可能引用两种(A
和{{1} })。但它给出了一个模棱两可的参考错误。
它是如何实际选择构造函数的?我通读了the docs,但坦率地说,我无法完全理解其如何确定特异性。我希望能够说明为什么它无法确定B
比E
更具体。
答案 0 :(得分:45)
它不是基于可转换为参数类型的类型数量 - 它是否由于隐式转换而对一个重载有效的值是否对另一个重载有效。
例如,有String
到Object
的隐式转换,但反过来并非如此,因此String
比{{1}更具体}}
同样地,从Object
到B
的隐式转换,但反过来并非如此,因此A
比B
更具体
然而,A
和A
都没有比另一个更具体 - 没有从E
到A
的转换,也没有来自E
的转换到E
。这就是重载解析失败的原因。
JLS的相关位实际上是15.12.2.5,其中包括这可能使您更容易理解:
非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个没有编译时错误的调用,那么一个方法比另一个方法更具体。
所以如果你有:
A
void foo(String x)
void foo(Object x)
处理的每个调用都可以由foo(String)
处理,但情况并非相反。 (例如,您可以拨打foo(Object)
并且foo(new Object())
无法处理。)
答案 1 :(得分:9)
在声明JSL§15.12.2.5答案后,
非正式的直觉是,一种方法更具体 另一个,如果第一个方法处理的任何调用都可以传递 没有编译时错误的另一个。
案例1
val v1 = sqlContext.parquetFile("hdfs://myhost:8020/user/hive/warehouse/db/blogs/yymmdd={[0-9]*}")
,而我们无法在第一个构造函数中传递Object
以外的任何内容。因此,无论我在Map
构造函数中传递的是什么,都可以由Map
构造函数处理,这就是为什么Object
变得特定于mote的原因。案例2
Test(Map map)
扩展B
以来,此处A
构造函数变得更加具体。由于继承,我们可以在Test(B b)
中传递B
。案例3
答案 2 :(得分:6)
此行为是因为E并不比A更具体,因为它们属于不同的层次结构,无法进行比较。因此,当您传递null时,Java无法知道要使用哪个层次结构。