Java:重载构造函数之间的选择

Java: selection between overloaded constructors

Per this question,Java 将 select "most specific" 选项当试图在不明确的重载构造函数之间 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);
    }
}

它将打印

"Map"

但是,我试图弄清楚 "most specific" 到底是什么意思。我假设它的意思是 "least ambiguous",如 "may refer to the fewest possible types." 在这种情况下,Object 可能是任何不是原始的东西,而 Map 可能只是 Map? extends Map。基本上,我假设哪个 class 更接近继承树的叶子将被 selected。当一个 class 是另一个的子 class 时,这有效:

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 可能指两种(AB).但它给出了一个模糊的引用错误。

它实际上是如何选择构造函数的?我通读了 the docs 但坦率地说,我不太明白它是如何确定特异性的。我希望能准确描述为什么它不能确定 EA.

更具体

此行为是因为 E 并不比 A 更具体,因为它们属于不同的层次结构,因此无法进行比较。因此,当您传递空值时,Java 无法知道要使用哪个层次结构。

它不是基于可转换为参数类型的类型的数量 - 由于隐式转换,它是对一个重载有效的任何值是否对另一个重载有效。

例如,存在从 StringObject 的隐式转换,但反之则不然,因此 StringObject 更具体。

同样存在从 BA 的隐式转换,但反之则不然,因此 BA 更具体。

然而,对于 AE,两者都不比另一个更具体 - 没有从 AE 的转换,也没有从 [=20] 的转换=] 到 A。这就是重载解析失败的原因。

JLS 的相关位实际上是 15.12.2.5,其中包括可能使您更容易理解的内容:

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

所以如果你有:

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

foo(String) 处理的每个调用都可以由 foo(Object) 处理,但反之则不然。 (例如,您可以调用 foo(new Object())foo(String) 无法处理。)

JSL§15.12.2.5 的以下陈述回答了

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

案例一

  • 您可以在采用 Object 的构造函数中传递任何内容,而我们不能在第一个构造函数中传递 Map 以外的任何内容。因此,无论我在 Map 构造函数中传递什么,都可以由 Object 构造函数处理,这就是为什么 Test(Map map) 变得具体。

案例二

  • 由于 B 扩展了 A,这里的 Test(B b) 构造函数变得更加具体。由于 继承 .
  • ,我们可以在 Test(A a) 中传递 B

案例三

  • 在这种情况下,没有直接转换来描述更具体的方法,这会导致 歧义