Java:在重载的构造函数之间进行select

根据这个问题 ,当尝试在模糊的重载构造函数之间进行select时,Java将select“最具体的”选项。 在这个例子中:

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); } } 

它会打印

“地图”

但是,我试图弄清楚“最具体”的含义。 我认为这意味着“最不明确”,就像“可能指的是尽可能less的types”。 在这种情况下, Object可能是任何不是原始的东西,而Map可能只是Map? extends Map ? extends Map 。 基本上,我认为select哪个类更靠近inheritance树的叶子。 当一个类是另一个类的子类时,这是有效的:

 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可能只指一种已知types,而A可能指两个( AB )。 但它给了一个模棱两可的参考错误。

它是如何select构造函数? 我仔细阅读了文档,但坦率地说,我不能完全按照它如何确定特殊性。 我希望能够说明为什么它不能确定EA更具体。

它不是基于可转换为参数types的types的数量 – 这是由于隐式转换,对于一个超载有效的值是否对另一个有效。

例如,有一个从StringObject的隐式转换,但是反过来却是不正确的,所以StringObject更具体。

同样也有从BA的隐式转换,但是反过来却是不正确的,所以BA更具体。

然而,对于AE ,两者都不是比另一个更具体 – 没有从AE转换,也没有从EA转换。 这就是重载解决失败的原因。

JLS的相关位实际上是15.12.2.5 ,其中包括这可以使你更容易理解:

非正式的直觉是,如果第一个方法处理的任何调用都可以传递给另一个方法而没有编译时错误,那么其中一个方法比另一个更具体。

所以如果你有:

 void foo(String x) void foo(Object x) 

每个由foo(String)处理的调用都可以由foo(Object)来处理,但事实并非如此。 (例如,你可以调用foo(new Object()) ,并且不能由foo(String)处理。)

在JSL§15.12.2.5的声明之后,

非正式的直觉是, 如果第一个方法处理的任何调用都可以传递给另一个方法而没有编译时错误 ,那么其中一个方法比另一个更具体

情况1

  • 你可以在构造函数中传递任何东西,而我们不能在第一个构造函数中传递除Map之外的任何东西。 所以,无论我在Map构造函数中传递什么,都可以通过Object构造函数来处理,这就是为什么Test(Map map)变得特定于mote的原因。

案例2

  • 由于B扩展了A ,所以这里Test(B b)构造函数变得更具体。 因为inheritance,我们可以在Test(A a)传递B

案例3

  • 在这种情况下,没有直接的转换来描述更具体的方法,并且导致模糊性

这种行为是因为E不是比A更具体,因为它们属于不同的层次结构,它们不能被比较。 因此,当你传递null时,Java不能知道使用哪个层次结构。